TR和TRW操作手册(一) 如果你用过 DEBUG , SYMDEB , TD ( TURBO DEBUG ), CV ( CODE VIEW )或 SOFT-ICE , 你应该试试 TR 。    TR (将)具有以上调试软件的一切功能,支持它们的所有命令。而且,最重要的是, TR 提出了九大新的思想:   一、解释跟踪    TR 对程序是解释执行的。 TR 就象是一个 CPU , 能读懂每一句程序代码并正确解释执行,不需要使用 INT1 , INT3 ,不需要使用 386 调试寄存器 DR0-DR7 ,不需要进入保护模式(是不会)。理论上, TR 永远不会被应用程序发现,永远不会有跟踪不下去的程序。因为所有的程序都要交给 CPU 去解释执行,只要 CPU 认识的指令, TR 也要认识, TR 会想象 CPU 处在这种状态会怎么作,那我也那么去作。如果你发现 TR 作错了,那是 TR 还尚待完善。   传统的跟踪方式有太多的弊病:   (1)那些使用单步中断 INT1 的调试软件,因为它们独占 INT1 和 TF ,所以那些需要 INT1 的应用程序便无法跟踪,应用程序也可以通过检测 TF 来发现自己是否正在被跟踪。   (2)那些使用断点中断 INT3 的调试软件, 需要在应用程序中插入代码 INT3 ( 0CCH ),如果应用程序破坏 INT3 的中断向量,或检测自身代码便无法跟踪。   (3) SOFT-ICE 不使用以上两种方法,而是用 386 硬件中断, 效果要好多了。跟踪那些对 386 一无所知的程序不成问题。但许多要求 EMM386 、 DPMI 、 DOS4GW 等的软件的运行受到了极大的限制,甚至根本不能在 SOFT-ICE 下执行。 更重要的是, SOFT-ICE 很容易被发现。   总之,现有跟踪调试软件都是利用 INTEL 的 CPU 手册上提供的规范的调试方法进行工作,它们只适合调试那些规规矩矩的、愿意被跟踪调试的程序。如果应用程序不予合作,便不能跟踪。 TR 则不同, TR 要跟踪所有 CPU 能处理的程序,甚至 TR 能嵌套跟踪另一个 TR 。   另一方面,传统的跟踪方法是设置好一些断点(不管是何种断点),然后 GO 到应用程序中去执行,并期望程序运行到适当地方, CPU 能产生一个中断,返回主程序。至于能否返回,或返回前程序干了些什么,只有天知道。用解释的方法跟踪,控制权永远牢牢掌握在 TR 的手中,监控着所有程序流程,并由此才能设置一些高度复杂的断点。   解释跟踪是 TR 与其它调试软件的最本质的区别。也是 TR 高性能的根本所在。   二、批处理   尽管批处理的概念很早就有,在各种软件中应用极为广泛,却无人把它作到调试软件中。在 TR 中,可以把要执行的命令序列放到一个文本文件中,用 DO 命令执行。当然还有自动批处理 AUTORUN.TR 。   三、 G OFFSET   对 G 100 命令,大家都知道是执行到 100 停下,其它的调试软件认为是到当前段的 100 停下, TR 却不管段址如何,只要 IP 是 100 便停下。 这样一般的 COM 外壳只要一条 G 100 便解决。这个功能看起来简单,却极为有用。有了这条命令,再也不用去记复杂的跟踪路径,只要把当前跟踪到的 IP 记下,下一次一 G 便到。   四、汇编指令作为命令   搞汇编语言的人满脑子都是汇编,复杂的调试命令可能不愿去记。能用汇编指令作为命令当然是个好主意。用 R AX   1234 当然不错,用 MOV AX , 1234 岂不更有意思?其它 CLI\MOV [WORD 1234],4567\IN AL,21 都是不错的命令。   五、允许对调试程序作注解   CALL 7F2E 看起来当然没有 CALL OPEN_FILE 容易理解,但跟踪调试却不得不面对大串的莫名其妙的代码。即使某个过程经过跟踪已经知道是干什么的,也只能写到纸上。如果能把跟踪结果写到屏幕上,那是什么概念!整个程序变成了你手上的一篇文章,可以对它任意地圈圈点点。每一次跟踪都添加一些新的见解,最后,整个程序一目了然。参见命令 LABEL 和 CMT 。   是这个功能使跟踪变成了一项真正可以做的工作。   六、自动跳转   最近加密界出现了一种新的技术,用 JMP 指令把代码扯乱。这样跟踪者一次只能看到一条指令和一个 JMP ,看不见来路也看不见去路,跟踪工作变得异常 " 艰难困苦 " 。 TR 的自动跳转技术使得在执行过程中不显示 JMP 指令,而把 JMP 后的指令直接放在 JMP 指令原来的位置。经过 TR 的重组,提高了代码的可读性。   参见命令 AUTOJMP 。   七、历史记录   TR 可以把执行过的每一个 CS:IP 记录下来,以便静态分析。如果程序出错, 可以查历史记录向前回溯,找到问题所在。更有功能强大的 LOGPRO ,可以把程序的关键指令整理出来。被跟踪程序再无任何秘密可言。   参见命令 LOG 、 LOGS 、 VLOG 、 LOGPRO 。   八、把内存代码写成 EXE 文件   从内存中重构 EXE 文件的技术已经十分成熟,各种万能脱壳软件到处都是,但都是盲目地脱。随便拿到一个文件在 INT21\AH=30 处脱一下是不能解决问题的。脱壳应该是跟踪调试软件的一项功能,跟踪到了,再脱,万无一失。   九、复杂的断点,一次性断点。   各种调试软件所能设置的断点都是 INTEL 当初设计 CPU 时就想好的几种,远远不能满足高级跟踪的要求。 TR 创造性地提出了许多断点:   ( 1 ) BP CONDITIONS   条件断点。如:   BP IP>4000   ; 代码较长,只跟踪后半部             BP AH=2 DL=80 CH>30   ( 2 ) BPINT intnum [CONDITIONS] 中断断点   ( 3 ) BPXB BYTES [CONDITIONS]   遇到指定指令就停下。如: MOV AX,???? 的机器码为 B8???? ,可用BPXB b8   其它: BPXB cd ; 所有中断 BPXB 33 C0 ;XOR AX,AX   ( 4 ) BPREG REG│SEG [CONDITIONS]   如果指定的寄存器改变,则暂停。 BPREG CS 可以找到所有的段跳。       BPREG CS AX=0 ES=#    ;# 指当前 PSP 可以找到带外壳程序的真正开始。   ( 5 ) BPM [SEG:]OFFSET   如果访问指定地址则暂停。如 BPM 20 将使 MOV AX,[20] 停下。   ( 6 ) BPW SEG:OFFSET   如果指定地址改变,则暂停。有些操作(如 INT )对内存的改变只有一次次检查是否改变才能找到。   ( 7 ) BPIO port [conditions]   ( 8 ) BPKNL [count]   如果发现新的程序内核,则暂停。   特别重要的是,如果一个断点只用一次,把设断点命令前面的 'BP' 改为 'GO' 或 'GS' 便可直接执行。有了这个一次性断点,一般根本不需要专门设置断点。   以上这些新增的断点,千百倍地提高了跟踪的效率,再也不需要苦苦地跟踪了!    TR 是真正的跟踪调试软件!尽管我们上面提到了 DEBUG,SYMDEB,TD,CV,S-ICE ,但哪一个是真正的跟踪调试软件? DEBUG 和 SYMDEB 当然不能算是, 因为我想跟踪软件至少应该是全屏幕的。 TD 居然没有命令行输入,没有什么鼠标操作能比一行命令 F CS:DX,DX+CX 00 更能简单准确地表达你的意图。在 DEBUG 中至少还可以 L100 0   01 检查软盘 BOOT 区,可以 L400 或 W400 把一个文件调入指定内存或把内存写成文件, 在 SYMDEB 中还可以用一个 > 号把反汇编结果存起来,可惜这些非常有用的功能其它软件都做不到。 TD 和 CV 不象是专门的调试软件,更象是为了对各自的C语言排错用的。 S-ICE 应该算是一个不错的跟踪调试软件了,但总是感觉 386CPU 的调试功能就是为 S-ICE 而留,而 S-ICE 也就是仅仅为了演示 386CPU 的调试功能。只有TR,真正为跟踪者着想,就软件的跟踪技术提出了九大新的思想,第一次使程序跟踪成为了一项真正可以为之的工作,TR是真正的跟踪调试软件!    TR 现在不支持 386 保护模式,不能处理 WIN95 程序。如果你要跟踪 DOS 保护模式程序, 16 位 Windows 程序, 32 位 Windows95 程序,请使用 TR for Win95: http://trw.yeah.net 在以后的版本中,这些问题将一一解决。   我一直在努力使 TR 达到完美,每天 TR 都有大的改变。请与我联系,你将获得最新版本。 作者 :  刘 涛 涛                          98.3.3 -----------------------------------------------------------------        须 知   一、 TR 支持 Turber Debuger 调拭信息。如果调试一个带调试信息的 C 语言程序,可以用 g _main 快速进入现场。   二、支持 32 位指令(见命令 r32 )   三、从 TR 中退出后,用户程序修改过的所有中断都将被自动恢复,占有的内存自动释放。   四、如果系统有 XMS , TR 自动使用,可以节省一些内存空间。   五、所有数字输入均采用十六进制。   运行 TR 需要 386 以上的 CPU ,在 DOS 下运行,也可以在 WINDOWS 和 WINDOWS95 的 DOS 窗口中运行,不过速度会更慢。与 HIMEM 或 EMM386 或任何其它的 XMS/EMS 内存管理软件兼容。可以很好地在 SOFT-ICE 下运行。 TR 只会跟踪实模式下的 DOS 程序,对保护模式和 WINDOWS 程序,请使用 TR for Win95 。 ----------------------------------------------------------------- 命令详解 ----------------------------------------------------------------- TR 的屏幕显示 EAX=00003000   EBX=00000000   ECX=00000000   EDX=00002755   SP=007E EBP=00000000   ESI=00000000   EDI=00000000   FS=0000   GS=0000 DS=2640   ES=2640   SS=2785   CS=2650   IP=000A   o d I s z a p c t 2640:0000   CD 20 FF 9F 00 9A F0 FE-1D F0 1E 44 FD 07 6D 01   ............ 2640:0010   13 06 78 01 13 06 13 06-01 01 01 00 02 FF FF FF   ..x......... 2650:0000   BA5527       MOV     DX,2755 2650:0003   2E89168B02     MOV     [CS:DGROUP@],DX 2650:0008   B430        MOV     AH,30 2650:000A   CD21        INT     21 Get MS-DOS Version Number 2650:000C   8B2E0200      MOV     BP,[0002] 2650:0010   8B1E2C00      MOV     BX,[002C] 2650:0014   8EDA        MOV     DS,DX 2650:0016   A37D00       MOV     [007D],AX 2650:0019   8C067B00      MOV     [__psp],ES 2650:001D   891E7700      MOV     [__envseg],BX 2650:0021   892E9100      MOV     [0091],BP 2650:0025   E85101       CALL     0179 2650:0028   A17700       MOV     AX,[0077] 2650:002B   8EC0        MOV     ES,AX 2650:002D   33C0        XOR     AX,AX Super Program Trace (test version), Written by Ld. 06/16/97 Press '?' for Help r32 Welcome !!!   Tel:0372-3932916-2273   EMAIL: ayliutt@hotmail.com   以上是 TR 的典型屏幕显示。主要有寄存器区、内存区、代码区、命令区、状态行。   一、寄存器区   屏幕的最上端是寄存器区。缺省为 16 位方式显示,可以用 R32 命令改为 32 位方式。   用 R 命令置寄存器值,如:     R AX 1234     R ebx 12321456     R ch 87     R dl ah     R ip ip+1     R fl z   对标志寄存器用 ODISZAPCT ,最近改变过的寄存器以不同颜色表示。   二、内存区。   内存区以十六进制和 ASCII 码方式显示内存内容。可以用 E 命令把光标转到内存区编辑,可以按左、右、上、下、上下翻页、 HOME 、 END 等键移动光标,按字母数字键修改内存,按 TAB 键十六进制 ASCII 码转换。也可以用 e offset 'content' 直接修改。   用 WD num 改变内存区的行数。   内存区有两种显示方式,一种是普通的段不变偏移连续变化的方式,另一种是段以 10H 变化,偏移为 0 的方式。普通方式下,用 E 命令使光标到内存区, 如果当前 OFFSET 小于 0F 按向上箭头,变为第二种显示方式。用 D 命令恢复。   三、代码区   屏幕中央是代码区,显示程序的汇编代码。支持 386 指令, 可以显示标号和注解,对常用中断进行解释。   四、命令区   用于输入命令。可以按 F5 键放大,按左、右、上、下、上下翻页、 HOME 、 END 等键移动光标,用 DEL 和 BACKSPACE 修改。   如果要多次执行一条命令,把光标放到那条命令上按 ENTER 。   五、状态行   显示命令是否正常执行。   六、以上是 TR 的主要窗口,另处还有 F4 显示用户屏幕, VIEW 命令列文件内容, STACK 命令显示 STACK 窗, VLOG 显示历史窗等等。 -----------------------------------------------------------------              常用按键   执行一句汇编指令,等同于命令 T 。   执行一个过程,等同于命令 P 。  显示用户屏幕,等同于命令 RS 。  命令窗 <--> 代码窗。  如果光标在代码窗,执行到光标位置 (HERE) 。  最大当前窗口。当前窗口可以是命令窗、代码窗、内存窗。  如果光标在代码窗,设置(或清除)光标所在位置为断点。   Ctrl+D 暂停程序的运行,返回 TR 。注意, TR 只会停留在被跟踪程序的代码中,而不会停留在系统代码中,所以按热键 Ctrl+D 后有时不会马上返回。 ---------------------------------------------------------------              常用符号   <$> :   在 TR 的命令中,可以用美元符 '$' 代表当前的 CS:IP 。命令 D CS:IP   与命令 D $   是等效的。命令 U $ 可以用命令 . 来代替。   <*> :   在 TR 的命令中,星号 '*' 代表当前指令的操作地址。如果当前的 CS:IP 为 ****:**** mov ax,[di] ;1234:5678=****   并且此时 DS=1234,DI=5678 ,则命令  D *   与命令  D DS:DI   或  D 1234:5678  等效。   <@>:   取地址的指针。比如,如果 1234:5678 11 22 33 44   则 @1234:5678 表示 4433:2211 。   可以用 @0:21*4 表示中断 21 的地址。   如果刚刚进入一个 CALL FAR 或 INT ,可以用 @ss:sp 返回。   <#>:   在 TR 的命令中,井号 '#' 代表当前程序的 PSP 值。   例: D #:0   <;>:   分号 ';' 代表注解,命令中分号后面的部分将不被解释。   AUTORUN.TR:   每次 TR 运行,都会自动执行当前目录下文件 AUTORUN.TR 中的命令。把你总是要   执行的命令加入 AUTORUN.TR 。如 R32 , AUTOINT1 ON 等。 ---------------------TR 定制命令 -------------------- COLOR [01 02 03 04 05 06 07 08 09 10]   如果不带参数,显示当前 TR 的颜色设置。如果带参数,必须是 9 个值,分别表示 1 :寄存器区 寄存器名 2 :寄存器区 寄存器值 3 :寄存器区 改变过的寄存器值 4 :代码区  一般代码 5 :代码区  当前 CS:IP 6 :代码区  标号或注解 7 :代码区  断点 8 :命令区  一般命令 9 :命令区  注解 a :状态栏   如: color 7 b e 7 e 2 4 17 36 76 MSG [x y]   显示信息窗。主要用在 DO 命令文件中作演示用。以后的命令都作为要显示的信息,空回车返回。 X , Y 为信息框的位置, -1 为自动右上角, -2 为居中。例: msg 20 5 this is first line message THIS IS SECOND LINE And third ; 空回车 VER   显示版本信息。 R32    16 位寄存器 /32 位寄存器切换。如果是 16 位状态,寄存器窗口显示为 AX=1234   BX=1234   CX=1234   DX=1234   SP=1234   BP=1234   SI=1234   DI=1234 DS=1234   ES=1234   SS=1234   CS=1234   IP=1234   o d i s z a p c t    32 位状态的显示为: EAX=12345678   EBX=12345678   ECX=12345678   EDX=12345678   SP=1234 EBP=12345678   ESI=12345678   EDI=12345678   FS=1234   GS=1234 DS=1234   ES=1234   SS=1234   CS=1234   IP=1234   o d i s z a p c t   无论何种状态,都不影响系统运行。缺省为 16 位,如果你喜欢 32 位状态,把 R32 加入文件 AUTORUN.TR 。 REDRAW   屏幕重画。 WD [lines]   设定内存窗口的行数。 --------------------- 输入 / 输出 命令 -------------------- A [address]   汇编。虽然代码窗能够识别 32 位代码, A 命令暂时不能处理 32 位代码。   将在以后的版本改进。可以直接用 'BEGIN:' 的方法定义标号。 A cs:0 start: ;define label mov ax,bx ;any asm code ;return to command mode D [address│range] [>filename]]   以十六进制和 ASCII 码方式显示内存,加 '>' 号把结果输出到文件,   如: D cs:ip D * D 1234:5678>myfile.txt D cs:0lffff>file D >file   如果指定文件不存在,则自动生成;如果已经存在,则追加。   缺省长度 40H 。 E [[ptr] bytes]   内存修改。如果不带参数,光标移到数据区,这时可以按左、右、上、下、   上下翻页、 HOME 、 END 等键移动光标,按字母数字键修改内存,按 TAB 键十六   进制 ASCII 码转换。例: E cs:0 12 23 45 'abc' E b800:200 36 24 E 234 'def',0d,0a,'$'   缺省段为 DS 。 F range bytes   填充。把内存区域用给定字串填充,如 F cs:0,ffff 12 23 45 'abc' F b800:0L200 36 24 F 234 'def',0d,0a,'$'   如果未指定长度,给定字串至少填充一次,相当于 E 命令。   缺省段为 DS 。 L [[SEG]:OFFSET] [FILENAME]   读文件到内存。注意与 RELOAD 的区别, L 仅仅是把文件读到指定内存区,而    RELOAD 是找到一块空闲内存调入,建立 PSP ,设置寄存器,准备执行。   缺省段为 DS ,缺省地址 DS:100 。   例: N c:\autoexec.bat L 100 N c:\command.com L 200 L DS:300 MYFILE.BIN L [SEG]:OFFSET DRIVE STARTSECTER SECTERS   从指定物理驱动器读取指定物理扇区。   例: L 100 0 0 1 ; 读 A 盘 BOOT 区 L 100 2 0 1 ; 读 C 盘 BOOT 区 N [filename]   如果不带参数,显示当前文件名。如果带参数,置文件名。如: N MYFILE.EXT   参见: W , L , RELOAD RELOAD [filename]   重新调入文件。如果文件名已被 N 命令修改,则调入新文件。   重置所有中断向量、内存区、寄存器。   有时程序上一次申请的内存不能完全释放,导致调入失败。可以 退出 TR 再进, EXE2 , RELOAD ,仍然可以 MKEXE 。 U [address│range] [>filename]]   反汇编,加 '>' 号把反汇编结果输出到文件,如: u cs:ip u $ u 1234:5678>myfile u cs:0lffff>file u >file   如果不给出反汇编长度,缺省 20H 。   如果指定文件不存在,则自动生成;如果已经存在,则追加。 W W [SEG]:OFFSET W [SEG]:OFFSET filename W [SEG]:OFFSET length filename   写内存到文件。文件长度为 BX:CX 或 length 。   缺省段为 DS ,缺省地址 DS:100 。   例: N test.com W 200 W es:300 myfile.com W cs:ip dx test.com W [SEG]:OFFSET DRIVE STARTSECTER SECTERS   向指定物理驱动器写指定物理扇区。   例: W 100 0 0 1 ; 写 A 盘 BOOT 区 WREG filename   把当前寄存器区内容写入文件。如文件存在则追加。 WMEM filename   把当前内存窗口内容写入文件。如文件存在则追加。 WCOD filename   把当前代码窗口内容写入文件。如文件存在则追加。 WCMD filename   把当前命令窗口内容写入文件。如文件存在则追加。 --------------------------RUNTIME 命 令 ------------------------- DELAY [time]   用于 DO 命令文件中,起延时作用。如果命令文件中改变了 DELAY 状态,切   记在文件尾用 DELAY 0 恢复。   注意设定延时为 16 进制。 DO filename * 新概念 *   执行批处理。指定一个文本文件,里面可以包含所有合法的 TR 命令(甚至   另一个 DO ),让 TR 自动执行。每次 TR 运行,都会自动执行当前目录下文件    AUTORUN.TR 中的命令,相当于每次 TR 启动,都会自动执行一个 DO AUTORUN.TR   在批处理文件中,如果一个命令行以空格开始, TR 直接处理该命令而不在   命令窗口显示(第一个空格被去掉)。   特别用法:把一个汇编程序前面加个 A 〈回车〉,让 TR 去汇编。   参见: DELAY,KEY KEY num   用于 DO 批处理文件中,模拟按键。给定的值为 MOV AX,0\INT 16 返回的值,   如:KEY 1C0D   ;回车 所有汇编指令--------------------------    TR 支持几乎所有汇编指令作为命令。虽然我们不一定非要这么做,但有时候   确实很方便,试试下面命令: mov ah,4c jmp 200 cli 定义标号或过程名 :   命令行中,输入一个字串加冒号,定义当前的 CS:IP 为给定标号。   在 A 命令后的汇编状态中,定义的是当前正在汇编的地址。   例,如当前 IP=100 ,输入 'START:' ,则 CS:100 为 START ,所有 JMP 100 都将   译为 JMP START 。   在命令行中,这是 'LABEL CS:IP labelname' 的简写。   参见: LABEL,CMT .   在代码窗显示当前 CS:IP 。   相当于 U CS:IP 或 U $ 。 ? [expresion]   帮助。如果不带参数, TR 自动 ZOOM 命令窗口,简要显示每一条命令的语法和   功能。可以用 Up/Down/PageUp/PageDown 上下滚动窗口, F5 恢复。   如果带参数, TR 对参数计算后显示结果,如: ? ax 显示 AX 内容 ? cx+dx 显示 CX+DX 的结果 ? # 显示当前 PSP ? @0:21*4 ? $+5 显示 CS:IP+5 CMT [SEG:]OFFSET COMMENT_STRING * 新概念 *   对程序进行注解。   地址如果不提供段址,默认当前 CS 。如果地址小于 PSP:0 或大于 PSP+2000:0 ,   认为是相对地址,否则认为是绝对地址。   注解串可以是任意长度的字串,但命令总长度不能超过 79 。如果包含空格或   保留小写,请用单引号 '' 括住。   对程序所作注解全部存入文件 ' 当前文件名 .cmt' ,这是一个文本文件,可   以直接编辑。下次 TR 调入程序时自动装入。   如果定义当前 CS:IP 名,可直接用 ' 标号名 :' 。   例:      cmt cs:200 'This is my comment string' PROC1:   参见: LABEL,SYMBOLS LABEL [SEG:]OFFSET LABEL_NAME     * 新概念 *   定义标号或过程名。   如果定义了标号或过程名,代码窗中将在该地址前留一行显示其名子,并把   所有 JMP 和 CALL 到该过程的语句翻译为 'CALL 过程名 ' 而不是通常那样    'CALL ????' 。   程序标号全部存入文件 ' 当前文件名 .cmt' ,这是一个文本文件,可以直接   编辑。下次 TR 调入程序时自动装入。   例:      LABEL cs:200 file_open   参见: cmt,SYMBOLS LOG [ON│OFF]            * 新概念 *   是否记录历史。如果 LOG ON ,则 TR 将把以后执行的每条指令地址记录下来,   可以用 VLOG 命令查看。本命令只记录最后 25 条地址,如果要所有记录,请   用 LOGS 命令。   利用 TR 的 LOG 功能可以使用一种新的分析程序的方法 , 那就是 " 走后门 " 。   比如一个程序错误退出,如果用通常的办法从程序开始进行跟踪,要走很   长的路才能找到问题所在。而用 TR 的 LOG 功能,就可以在程序异常退出后分   析程序最后执行的什么过程,快速找到关键。 LOGS [ON│OFF]           * 新概念 *   是否记录历史。如果 LOGS ON ,则 TR 将在当前目录下建一文件 LOG.DAT ,   并把以后执行的每条指令地址以十六进制存入该文件。方便以后分析程序   流程。视程序复杂度,该文件可能会很长。请使用专门的十六进制浏览器   浏览该文件,或用 TR 的 VIEW 命令。   当 LOGS ON 时,因为执行每一条指令都会有一次存盘,速度较慢,一般情况   下,用 LOG ON 就足够了。 LOGS ON 时, LOG 自动为 ON 。 LOGPRO [0│1│2│f]           * 新概念 *   功能:把程序执行过的关键代码记录下来,便于分析。特别适合于正确   流程和错误流程的比较。   如果不带参数,则显示当前选项。各选项的意义: 0: 不 LOG 1: 只 LOG 以下几条指令 call,ret 2: 只 LOG 以下几条指令 call,ret,condition jmp,jmp far 注意:对 CONDITION JMP 只有条件为真时才 LOG f: LOG 所有指令   LOGPRO 把 LOG 的指令存到文件 LOGPRO.DAT ,每条记录长 16 字节,格式:   位置   大小  意义 0 DW IP 2 DW CS 4 DW SP 6 DB ? 7 DB ? 8 8 byte 指令码   在 DOS 提示符下执行 LOGPRO.EXE ,读取 LOGPRO.DAT ,生成 LOGPRO.TXT 。   这就是程序的关键代码。   特别感谢 LX 首先提出这个思想。 M RANGE [SEG]:OFFSET   内存复制。如:          M $L200 8000:100      ; 复制 CS:IP 开始长度 200 到 8000:100          M DS:0,800 ES:200     ; 复制 DS:0,800 到 ES:200 Q   退出 TR 。也可以按 ALT+X 。   用户程序修改过的所有中断都将被自动恢复,占有的内存自动释放。 R REG [num]   改寄存器值。可以是 8 位 16 位 32 位通用寄存器、标志寄存器 FL 或段寄存器。   对标志寄存器的操作可以是 ODISZAPCT 。   例: R ax 1234 R ebx 12321456 R ch 87 R dl ah R fl z RS   显示用户屏幕( Restore Screen ),热键 F4 。按任意键返回。 S range bytes   在内存中查找指定内容,如: s cs:0,ffff 12 34 45 ; 在 CS:0 到 ffff 中寻找 12 34 45 s ds:200l100 23 ; 在 DS:200 长度 100 中寻找 23 SYM [ON│OFF]   是否调入 EXE 文件的调试信息。缺省为ON。如果不想调入文件的调试信息,   先不带参数执行TR,然后:             SYM OFF             N myfilename             RELOAD   因为有些错误的调试信息会使 TR 发疯。 SYMBOLS   如果程序带有调试信息或用 label,cmt 命令自定义了符号,则显示所有符号名。   参见: CMT,LABEL VLOG   显示 LOG ON 或 LOGS ON 命令记录的历史信息。 VIEW filename.ext   浏览文件。可以以十六进制和 ASCII 方式查看文件内容。 STACK * 新概念 *   显示当前子程序嵌套状况。   比如,可以用 GOIO 378 找到关键指令,用 STACK 看当前 CS:IP 是经过几次    CALL 过来的,迅速找到关键子程序。   参见: PRET ---------------------------跟踪执行命令--------------------------- G G [seg:]offset G conditions * 新概念 *   执行程序,也可以用命令 GO 。如果条件满足,则暂停。   注意:在程序中加入 INT3 并不能使 G 命令的运行中止。   特别推荐: G OFFSET 。只要程序执行中 IP 等于设定的 OFFSET ,就会停下。你   不用担心段址在哪儿,代码是否动态生成。只要知道它会经过那儿,就会停   下。例: G 100 G CS:100 G BX G AH=4C G AX=0 BX=0 CX=0 G IP>400   参见: GS GO??? * 新概念 *   任何设置断点的命令 BP??? 都可以用 GO??? 来使用,用为一次性断点。   例: GOREG CS GOINT 21 AH=30 GOW ES:DI GOXB CD 13 AH=2   参见: GS??? GS    G 命令在执行前会恢复用户屏幕,执行结束后再保存用户屏幕。有些程序破   坏了 BIOS ,这样保存的屏幕信息无法正常恢复,对此问题 TR 还找不到好的解   决方法,于是增加了一个 GS 命令。 GS 命令相当于 G 命令,只是不恢复屏幕。   等价于执行多个 T 。 GS???   同 GO??? 命令,只是不恢复屏幕。参见: GS GO??? T   执行一句汇编指令,相当于按 F8 。   注意, TR 的 T 命令与其它调试器不太一样。 TR 并不会真的去执行这条指令,   而是完成每条指令的功能而已。如果遇到了 TR 无法识别的指令,只有用 TT   命令了。   如果遇到 INT 指令, T 命令不会进入系统的中断例程,因为我认为我们一般感   兴趣的是被跟踪程序,而不是系统。如果程序修改了 INT 地址, T 命令会进入   被改后的地址。如果真是需要进入中断,可以用 GG ,如 GG @0:21*4 ;进入 INT21 GG [[SEG:]OFFSET]   无条件执行, TR 不对执行过程作任何控制。   缺省段为 CS 。如果指定地址,那么 TR 在指定地址插入 CALL FAR 指令,然后 JMP   到应用程序中去,希望它能执行到这个 CALL FAR 由 TR 重新控制。之所以不用    INT3 是为了防止应用程序修改 INT3 中断向量。   因为这时程序的执行已不是 TR 的解释执行,所以运行速度正常。   仍然可以希望 CTRL+D 能回到 TR 的控制。 P   执行一个过程( F10 )。如果当前指令是一条 CALL 或 CALL FAR ,则执行整个过   程直到返回。如果是其它指令,同 T 。   如果确实想执行到下一步为止,比如遇到一个 LOOP ,请用命令 PP 。 PP   执行直到下一条指令。相当于 G IP+ 本指令长度。 PRET   执行程序直到 RET 、 RETF 或 IRET 指令。用于快速退出子程序。   参见: STACK TT   使用单步中断执行一条指令。   不推荐使用。   参见: int1 AUTOINT1 [ON│OFF]   这是一个标志,可以设为 ON 或 OFF 。缺省为 OFF 。   当为 ON 时,如果 TR 遇到一条不可识别指令,则自动用 INT1 单步中断去执行。   参见: TT,INT1 INT1 [ON│OFF]   这是一个标志,可以设为 ON 或 OFF 。缺省为 OFF 。   当为 ON 时, TR 不再解释每一条指令,而是用 INT1 单步中断去执行。   不推荐使用 ON 的状态。如果你确认 TR 对某条指令的解释有误,可用状态 ON   继续执行。如果只在此状态下执行一条指令,用命令 TT 。   影响命令: T , G , P 等   参见: TT,AUTOINT1 AUTOJMP [ON│OFF] * 新概念 *   设置是否自动跳转。如果为 ON ,在执行过程中 TR 将不显示 JMP 指令,而把 JMP 后的指令直接放在 JMP 指令原来的位置,并在该指令前加 "- 〉 " 符号以示区别。 这样在一些 JMP 过多的场合能使你容易保持清醒。如果你不习惯,让它 OFF 。   缺省为 ON 。 ------------------------------断点命令----------------------------    **** 如果断点只使用一次,把 BP???? 改为 GO???? 或 GS???? **** BL   列出所有断点。最多可设 8 个断点。   实际上是 9 个断点,断点 0 被 GO 系列命令占用。 BC [NUM]   清除所有断点或指定断点。 BD [NUM]    DISABLE 所有或指定断点。 BE [NUM]   允许所有或指定断点。 BPW segment:offset * 新概念 *   监视内存变化,如果指定位置的字( WORD )发生改变,则暂停。   如果设定此类断点, TR 每执行一条语句都会进行一次比较。 BP [seg:]offset * 新概念 *   如果执行到 CS:IP=SEG:OFFSET 或 IP=OFFSET ,则暂停。   用 BP seg:offset 时, TR 不会象通常的调试程序那样,插入一个 INT3 , TR 从   来不那样做,所以不用担心应用程序会发现或破坏 INT3 地址而不能返回。   用 BP offset 是个好主意,这样就不用关心它的段址是如何变化,在此之前   有多少代码的扭曲,断点区是否动态生成,都不用去管它。只要程序执行   过程中 IP=offset ,就会停下来。   这个断点实际上是下面 BP conditions 的一种特殊情况,也可以写作 BP ip=?? cs=??    TR 把它们作为一种情况进行处理。   惯用法:对 COM 文件脱壳,用 BP 100 或直接 G 100 。   例: bp cs:200 bp $+20 bp dx BP ip>200 BP conditions * 新概念 *   如果指定条件满足,则暂停,如 bp ax=1234 ; 当 ax 等于 1234H 时停 bp ax=0 bx=0 cx=0 ; 当 AX , BX , CX 同时为 0 时停 bp ah=3 dx=80   可同时设定 3 个条件,只有同时满足时,才有效。   条件判断可用 =,!=,>,<,>=,<= 。第一个参量用寄存器,可以用任何 8 位 16 位   寄存器或段寄存器,第二个参量用立即数(如果用寄存器,则取值)。 BPREG REG│SEG [conditions]   如果指定寄存器改变,并且条件满足,则暂停。   可以指定任意 16bit 通用寄存器或段寄存器。   特别推荐使用 bpreg cs AX=0 DX=0 ES=# ,一般可用来快速查找加外壳程序   真正的开始。   条件设置参见 BP 。 BPXB bytes [conditions]   如果执行到批定的机器码,则暂停。如,因 NOP 的机器码是 90H ,所以 BPXB 90   在运行过程中遇到 NOP 会停下。又如, MOV AX,???? 的机器码为 B8???? ,可用 BPXB b8   其它: BPXB cd ; 所有中断 BPXB 33 C0 ;XOR AX,AX   指定机器码长度不要超过 8 个字节。还可以加条件,如 BPXB cd 13 ah=3   条件设置参见 BP 。 BPINT intnum [conditions]   中断断点。如果执行指定中断,则暂停。如:      BPINT 21 AH=30      BPINT 13 AX=201 CH>30 DX=1 BPKNL [count] * 新概念 *   如果 AX=BX=SI=DI=BP=0 , DS=ES= , IP=0 或 IP=100 或 CS 刚发生变化   (意味着刚有过一次 JMP FAR 或 RET FAR ),则暂停。一般用于寻找有外   壳的程序内核。注意有些加壳软件并不严格符合这个条件,用此方法可   能会漏掉。如果你有比此更好的主意,请告诉我。   万能的办法常常不是最好的办法。 ----------------------------其它命令------------------------------ EXE1 EXE2 WEXE1 WEXE2 GETKNL [count]   参见下面《如何输出 EXE 文件》 ------------------------如何输出 EXE 文件-------------------------   有时我们跟踪一个外壳型程序,我们不仅希望能跟踪到文件的真正开始, 还希望能够恢复源文件。为此, TR 提供了生成 EXE 文件的功能。因为 COM 文件 比较简单,只要用 W 写内存到文件即可。下面重点介绍生成 EXE 文件的过程。   一、手工完成   首先,要把内存中的代码写成文件,应该知道文件的大小。为了达到这 个目的,先用命令 EXE1 把内存清掉,再用 RELOAD 重新调入,这样写盘时被使 用过的内存区域就是要存文件。   然后,用各种跟踪命令跟踪程序,对一般的外壳,用 goreg cs ax=0 bx=0 或 goknl 几次都能找到真正的文件头,用 WEXE1 存盘,生成文件 MEM1.DAT 。   为了处理 EXE 文件的重定位,需要把程序换个内存地址调入以进行比较。使用命令 EXE2 ,把内存挤掉一点并清除, RELOAD 。   仍然用上面的跟踪步骤跟踪到文件头,用 WEXE2 存盘,生成文件 MEM2.DAT 。   用 Q 命令退出 TR ,执行文件 MKEXE ,自动读取 MEM1.DAT 和 MEM2.DAT 中的信息,生成 EXE 文件 MEM.EXE ,你可以试着执行了!   二、让 TR 自动完成   用 TR 把程序调入,用命令 GETKNL [count]   其中 count 为脱几层外壳,缺省为 1 。 TR 会自动运行: exe1 reload goknl count wexe1 exe2 reload goknl count wexe2 q    TR 生成两个文件 mem1.dat 和 mem2.dat 并退出。在 DOS 提示符下运行 mkexe [orgfile.exe]   会生成文件 mem.exe ,这就是脱壳后的文件!   之所以把 MKEXE 单独作为一个文件而不是把它做到 TR 中去,是为了给大家扩充的机会。如果你对 MKEXE 感兴趣,可以索取 MKEXE 的源程序( C++ )。    MEM1.DAT 和 MEM2.DAT 包含一个 0x20 长的文件头: 偏移 大小 内容 00    word   0xac,0xbc 标志 02    word   PSP+0x10, 是程序代码在内存中的开始段址        MEM1.DAT 和 MEM2.DAT 应该不同以便确定重定位 04    word   CS-PSP-0x10 ,代码段偏移,两文件应相等。 06    word   IP 值,两文件应相等。 08    word   SS-PSP-0x10 ,堆栈段偏移,两文件应相等。 0a    word   SP 值,两文件应相等。 0c    word  程序内存块长度,以节( 10H )为单位         dw 09h dup(0)  其余为 0 后面接内存中代码。   不要希望 MKEXE 生成的 EXE 文件与源文件一模一样,那是不可能的。它们在功能上是一样的。如果你选择生成 EXE 的时机不太好,不正好是程序原来的开始,你还需要加一段代码恢复各寄存器值。   如果原文件带有 OVERLAY ,或在执行过程中检查自身,新的 EXE 文件可能不能直接执行。可以让 MKEXE 在 EXE 前加一段代码,修改环境块,使程序认为是那个未脱壳的程序在运行。用法: MKEXE ORGFILE.EXE ,文件名不要带路径。执行时,把脱壳前文件与脱壳后文件放一个目录中执行。   特别用法:你可以打开一个 COM 文件, tr mycom.com exe1 reload wexe1 exe2 reload wexe2 q mkexe ren mem.exe myexe.exe 这就是 COM2EXE ,把一个 COM 文件变为 EXE 文件! ----------------------------------------------------------------- 后 话    TR 比其它跟踪程序提供了许多新的功能,只要一个程序能在 TR 内用 G 执行,对它解密是一件非常简单的事。如果你发现一个程序 TR 不能正常处理(暂不考虑保护模式和 WINDOSE 程序),请送给我,我会马上送上新版 TR !   用解释的方法进行程序跟踪,是对程序进行虚拟机仿真执行。我相信,这种方法能够处理所有的计算机程序。   我会为之努力,我将更加努力。 刘 涛 涛                     一九九七年十月二十一日 (v1.92)