反汇编旧的 .COM 文件。卡在 48 字节以内。字节序问题?
Disassembling an old .COM file. Stuck within 48 bytes. Endian problem?
我有一个老游戏...Starflight。我认为它是在 86 年问世的。 IBM PC jr 的美好时光。我想我应该拆开一个反汇编器看看它是如何工作的。我可以在我解码的那一点上看到,代码大小肯定是优化过的……但我最终跳转到了文件外部的地址。这毫无意义。
我在下面的列表中添加了评论;它们是我的“想法”。
直到加载其他文件,我假设,int 0x3d
或 int 0x0f
...因为所有段寄存器都指向相同的内存段....并且该段是代码段, .COM 文件,每个内存引用或跳转都应保留在文件中。是吗?
Starflt.com
00000000 FA CLI ;Prevent interrupts
00000001 8CC8 MOV AX,CS ;Copy code segment to all segments
00000003 8ED0 MOV SS,AX
00000005 8EC0 MOV ES,AX
00000007 8ED8 MOV DS,AX
00000009 BE2901 MOV SI,word 0x0129 ;SI = 0x0129
0000000C 8B7C02 MOV DI,word [SI+0x02] ;DI = 0x3c15 (SI+2)
0000000F 47 INC DI
00000010 47 INC DI ;DI = 0x3c17
00000011 BB0507 MOV BX,word 0x0705 ;BX = 0x0705
00000014 8B1F MOV BX,word [BX] ;BX = 0xa924
00000016 81C30001 ADD BX,word 0x0100 ;BX = 0xaa24
0000001A 8BE3 MOV SP,BX ;SP = 0xaa24 (0x0e41)
0000001C 81C38000 ADD BX,word 0x0080 ;BX = 0xaaa4
00000020 8BEB MOV BP,BX ;BP = 0xaaa4 (0x0bae)
00000022 FB STI ;Restore Interrupts
00000023 FC CLD ;Clear direction flag
00000024 AD LODSW ;AX = DS:SI = 0xfa13
00000025 8BD8 MOV BX,AX ;BX = 0xfa13
00000027 FF27 JMP word [BX] ;Past COM EOF (0xd3a7)
内存:
00000705 24 byte 0x24 '$'
00000706 A9 byte 0xA9 '©'
00000129 13 byte 0x13
0000012A FA byte 0xFA 'ú'
0000012B 15 byte 0x15
0000012C 3C byte 0x3C '<'
0000AA24 41 byte 0x41 'A'
0000AA25 0E byte 0x0E
0000AAA4 AE byte 0xAE '®'
0000AAA5 0B byte 0x0B
您正在反汇编的程序是DOS COM程序。您通常有正确的想法,但您的内存偏移量不正确。 DOS COM 程序加载到内存中,从内存中的空闲段开始,该段内的偏移量为 0x100。前 0x100 个字节是 DOS Program Segment Prefix (PSP)。您正在从偏移量 0x0000 进行反汇编,因此在尝试解码 COM 程序时使用了错误的内存地址。
不清楚您使用的是什么反汇编程序,如果您使用 ndisasm
,您可以使用 -o
选项更改原点。如果你实际上没有使用 ndisasm
,你将不得不告诉你正在使用的反汇编器你想要一个 0x0100 而不是 0x0000 的原点。在 ndisasm
的情况下,您可以使用:
ndisasm -o 0x100 -b16 Starflt.com
我在网上找到了 Starflight 的副本,它似乎与您的代码相似。我使用 -o 0x100
得到的输出是:
00000100 FA cli
00000101 8CC8 mov ax,cs
00000103 8ED0 mov ss,ax
00000105 8EC0 mov es,ax
00000107 8ED8 mov ds,ax
00000109 BE2901 mov si,0x129 ; si = 0x129
0000010C 8B7C02 mov di,[si+0x2] ; di = 0x078a
0000010F 47 inc di
00000110 47 inc di ; di = 0x078c
00000111 BB0507 mov bx,0x705
00000114 8B1F mov bx,[bx] ; bx = 0xd4b6
00000116 81C30001 add bx,0x100 ; bx = 0xd5b6
0000011A 8BE3 mov sp,bx ; sp = 0xd5b6
0000011C 81C38000 add bx,0x80 ; bx = 0xd636
00000120 8BEB mov bp,bx ; bp = 0xd636
00000122 FB sti
00000123 FC cld
00000124 AD lodsw ; ds:si = ds:0x129 . ax = 0x0937
; si=si+2, si=0x12B
00000125 8BD8 mov bx,ax ; bx = 0x0937
00000127 FF27 jmp [bx] ; jmp to cs:0x224c
00000129 37 aaa
0000012A 098A0700 or [bp+si+0x7],cx
[snip]
00000704 F7B6D4E6 div word [bp-0x192c]
[snip]
00000937 4C dec sp
00000938 22DB and bl,bl
[snip]
0000224C 43 inc bx ; Execution will continue here
0000224D 43 inc bx
0000224E 4D dec bp
0000224F 4D dec bp
00002250 897600 mov [bp+0x0],si
00002253 8BF3 mov si,bx
00002255 AD lodsw
00002256 8BD8 mov bx,ax
00002258 FF27 jmp [bx]
如您所见,jmp [bx]
最终在 cs:0x224c 处开始执行,恰好在该程序的内存中。
如果您想像这样单步执行旧的 16 位实模式代码,我建议您使用 Turbo Debugger 并使用像 DOSBox 这样的 DOS 模拟器。 Starflight 将 运行 在 DOSBox 中。
我有一个老游戏...Starflight。我认为它是在 86 年问世的。 IBM PC jr 的美好时光。我想我应该拆开一个反汇编器看看它是如何工作的。我可以在我解码的那一点上看到,代码大小肯定是优化过的……但我最终跳转到了文件外部的地址。这毫无意义。
我在下面的列表中添加了评论;它们是我的“想法”。
直到加载其他文件,我假设,int 0x3d
或 int 0x0f
...因为所有段寄存器都指向相同的内存段....并且该段是代码段, .COM 文件,每个内存引用或跳转都应保留在文件中。是吗?
Starflt.com
00000000 FA CLI ;Prevent interrupts
00000001 8CC8 MOV AX,CS ;Copy code segment to all segments
00000003 8ED0 MOV SS,AX
00000005 8EC0 MOV ES,AX
00000007 8ED8 MOV DS,AX
00000009 BE2901 MOV SI,word 0x0129 ;SI = 0x0129
0000000C 8B7C02 MOV DI,word [SI+0x02] ;DI = 0x3c15 (SI+2)
0000000F 47 INC DI
00000010 47 INC DI ;DI = 0x3c17
00000011 BB0507 MOV BX,word 0x0705 ;BX = 0x0705
00000014 8B1F MOV BX,word [BX] ;BX = 0xa924
00000016 81C30001 ADD BX,word 0x0100 ;BX = 0xaa24
0000001A 8BE3 MOV SP,BX ;SP = 0xaa24 (0x0e41)
0000001C 81C38000 ADD BX,word 0x0080 ;BX = 0xaaa4
00000020 8BEB MOV BP,BX ;BP = 0xaaa4 (0x0bae)
00000022 FB STI ;Restore Interrupts
00000023 FC CLD ;Clear direction flag
00000024 AD LODSW ;AX = DS:SI = 0xfa13
00000025 8BD8 MOV BX,AX ;BX = 0xfa13
00000027 FF27 JMP word [BX] ;Past COM EOF (0xd3a7)
内存:
00000705 24 byte 0x24 '$'
00000706 A9 byte 0xA9 '©'
00000129 13 byte 0x13
0000012A FA byte 0xFA 'ú'
0000012B 15 byte 0x15
0000012C 3C byte 0x3C '<'
0000AA24 41 byte 0x41 'A'
0000AA25 0E byte 0x0E
0000AAA4 AE byte 0xAE '®'
0000AAA5 0B byte 0x0B
您正在反汇编的程序是DOS COM程序。您通常有正确的想法,但您的内存偏移量不正确。 DOS COM 程序加载到内存中,从内存中的空闲段开始,该段内的偏移量为 0x100。前 0x100 个字节是 DOS Program Segment Prefix (PSP)。您正在从偏移量 0x0000 进行反汇编,因此在尝试解码 COM 程序时使用了错误的内存地址。
不清楚您使用的是什么反汇编程序,如果您使用 ndisasm
,您可以使用 -o
选项更改原点。如果你实际上没有使用 ndisasm
,你将不得不告诉你正在使用的反汇编器你想要一个 0x0100 而不是 0x0000 的原点。在 ndisasm
的情况下,您可以使用:
ndisasm -o 0x100 -b16 Starflt.com
我在网上找到了 Starflight 的副本,它似乎与您的代码相似。我使用 -o 0x100
得到的输出是:
00000100 FA cli 00000101 8CC8 mov ax,cs 00000103 8ED0 mov ss,ax 00000105 8EC0 mov es,ax 00000107 8ED8 mov ds,ax 00000109 BE2901 mov si,0x129 ; si = 0x129 0000010C 8B7C02 mov di,[si+0x2] ; di = 0x078a 0000010F 47 inc di 00000110 47 inc di ; di = 0x078c 00000111 BB0507 mov bx,0x705 00000114 8B1F mov bx,[bx] ; bx = 0xd4b6 00000116 81C30001 add bx,0x100 ; bx = 0xd5b6 0000011A 8BE3 mov sp,bx ; sp = 0xd5b6 0000011C 81C38000 add bx,0x80 ; bx = 0xd636 00000120 8BEB mov bp,bx ; bp = 0xd636 00000122 FB sti 00000123 FC cld 00000124 AD lodsw ; ds:si = ds:0x129 . ax = 0x0937 ; si=si+2, si=0x12B 00000125 8BD8 mov bx,ax ; bx = 0x0937 00000127 FF27 jmp [bx] ; jmp to cs:0x224c 00000129 37 aaa 0000012A 098A0700 or [bp+si+0x7],cx [snip] 00000704 F7B6D4E6 div word [bp-0x192c] [snip] 00000937 4C dec sp 00000938 22DB and bl,bl [snip] 0000224C 43 inc bx ; Execution will continue here 0000224D 43 inc bx 0000224E 4D dec bp 0000224F 4D dec bp 00002250 897600 mov [bp+0x0],si 00002253 8BF3 mov si,bx 00002255 AD lodsw 00002256 8BD8 mov bx,ax 00002258 FF27 jmp [bx]
如您所见,jmp [bx]
最终在 cs:0x224c 处开始执行,恰好在该程序的内存中。
如果您想像这样单步执行旧的 16 位实模式代码,我建议您使用 Turbo Debugger 并使用像 DOSBox 这样的 DOS 模拟器。 Starflight 将 运行 在 DOSBox 中。