关于编程大赛一等奖获得者的 4K 程序浅析
程序的自解压模块:
13B3:0100 33F6 XOR SI,SI ; 源偏移为 0
13B3:0102 BF0020 MOV DI,2000 ; 目的起始地址 2000H
13B3:0105 B510 MOV CH,10 ; 计数器为 1000H
13B3:0107 F3 REPZ
13B3:0108 A5 MOVSW ; 实际移动 2000H bytes
以上将全部数据移动至偏移为 2000H 开始的内存空间
13B3:0109 8CC8 MOV AX,CS
13B3:010B 050002 ADD AX,0200
13B3:010E 50 PUSH AX
13B3:010F 68 DB 68 ; 这里 DEBUG 不支持
13B3:0110 1301 ADC AX,[BX+DI] ; 以下为 INTEL 的定义
; 68 - PUSH imm16
; 68 - PUSH imm32
13B3:0112 CB RETF
以上转移至复制后的代码以便解压
以下解压缩,源数据在 01A1,目的地址从 0100 开始,因此最终的程序长度可从 DI 得出
13B3:0113 0E PUSH CS
13B3:0114 1F POP DS
13B3:0115 BEA101 MOV SI,01A1
13B3:0118 BF0001 MOV DI,0100
13B3:011B 06 PUSH ES
13B3:011C 57 PUSH DI
13B3:011D B81101 MOV AX,0111
13B3:0120 BB2113 MOV BX,1321
13B3:0123 8907 MOV [BX],AX
13B3:0125 4B DEC BX
13B3:0126 4B DEC BX
13B3:0127 48 DEC AX
13B3:0128 79F9 JNS 0123
13B3:012A AD LODSW
13B3:012B 86E0 XCHG AH,AL
13B3:012D 8BC8 MOV CX,AX
13B3:012F BDFFFF MOV BP,FFFF
13B3:0132 E82000 CALL 0155
13B3:0135 3D0001 CMP AX,0100 ;
13B3:0138 741A JZ 0154 ; 这里判断是否解压完成
13B3:013A 7F03 JG 013F
13B3:013C AA STOSB
13B3:013D EBF3 JMP 0132
13B3:013F 2DFF00 SUB AX,00FF
13B3:0142 50 PUSH AX
13B3:0143 E80F00 CALL 0155
13B3:0146 5A POP DX
13B3:0147 F7D8 NEG AX
13B3:0149 8BD8 MOV BX,AX
13B3:014B 26 ES:
13B3:014C 8A01 MOV AL,[BX+DI]
13B3:014E AA STOSB
13B3:014F 4A DEC DX
13B3:0150 75F9 JNZ 014B
13B3:0152 EBDE JMP 0132
13B3:0154 CB RETF ; 从这里是返回
; 解压后代码头
以下为一个子过程
13B3:0155 57 PUSH DI
13B3:0156 BB2113 MOV BX,1321
13B3:0159 8BC1 MOV AX,CX
13B3:015B 40 INC AX
13B3:015C F727 MUL WORD PTR [BX]
13B3:015E F7F5 DIV BP
13B3:0160 8BFB MOV DI,BX
13B3:0162 BA1101 MOV DX,0111
13B3:0165 4F DEC DI
13B3:0166 4F DEC DI
13B3:0167 4A DEC DX
13B3:0168 3905 CMP [DI],AX
13B3:016A 7FF9 JG 0165
13B3:016C 52 PUSH DX
13B3:016D 8BC5 MOV AX,BP
13B3:016F F725 MUL WORD PTR [DI]
13B3:0171 F737 DIV WORD PTR [BX]
13B3:0173 2BC8 SUB CX,AX
13B3:0175 95 XCHG BP,AX
13B3:0176 F76502 MUL WORD PTR [DI+02]
13B3:0179 F737 DIV WORD PTR [BX]
13B3:017B 95 XCHG BP,AX
13B3:017C 2BE8 SUB BP,AX
13B3:017E FE0EFE10 DEC BYTE PTR [10FE]
13B3:0182 7906 JNS 018A
13B3:0184 C606FE1007 MOV BYTE PTR [10FE],07
13B3:0189 46 INC SI
13B3:018A D014 RCL BYTE PTR [SI],1
13B3:018C D1D1 RCL CX,1
13B3:018E D1E5 SHL BP,1
13B3:0190 79EC JNS 017E
13B3:0192 5A POP DX
13B3:0193 B81101 MOV AX,0111
13B3:0196 FF07 INC WORD PTR [BX]
13B3:0198 4B DEC BX
13B3:0199 4B DEC BX
13B3:019A 48 DEC AX
13B3:019B 3BD0 CMP DX,AX
13B3:019D 75F7 JNZ 0196
13B3:019F 5F POP DI
13B3:01A0 C3 RET
这里我不想对其解压缩算法以及其对应的压缩算法进行深究,
仅讨论该程度的源数据获得。
至于其实际代码的执行过程我就不再给出源代码,有兴趣者可以自己反编。
其代码在执行过程中却是修改了部分数据,
因此通过在程序执行后用 ESC 退出的方法不能保证程序在修改数据之前停止,
由此得到的程序在执行过程出现问题时很正常的了。
建议可在程序执行到
“ 0154 CB RETF ” 时停止,将 0100 开始的数据写入 .COM 文件即可,
程序长度可通过 DI 获取。