【问题标题】:Disassembling an old .COM file. Stuck within 48 bytes. Endian problem?反汇编旧的 .COM 文件。卡在 48 个字节内。字节序问题?
【发布时间】:2026-01-05 11:25:03
【问题描述】:

我有一个老游戏……星际飞行。我想它是在 86 年问世的。好 ol' IBM PC jr 日子。我想我会破解一个反汇编程序,看看它是如何工作的。我可以看到我已经解码的一点点,代码大小肯定是优化的......但我最终跳转到了文件外部的地址。这没有任何意义。

我在下面的列表中添加了 cmets;它们是我的“想法”。

直到其他文件被加载,我假设,int 0x3dint 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

【问题讨论】:

  • 小世界。如果你认出我肩膀上那漂亮的蓝色,IDK。 (Schlumberger) 我刚拿到 CS 硕士学位。只需要说服某人我值得我的盐。

标签: assembly dos x86-16 disassembly


【解决方案1】:

您要反汇编的程序是一个 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 中运行。

【讨论】:

  • 谢谢。我确实抓住了 DOSBox 并且已经玩了几个小时。 :D 我查看并找到了 TaTraDAS 进行拆卸。我还使用了“在线反汇编程序”。两者都提出了相同的指示。认为是我的大脑抓取了错误的字节。 “ODA”可以按预期进行抵消。还没有真正弄清楚TDAS。我花了一些时间在 VS17 中使用内联汇编程序来查看要抓取哪些。失败的。 TYVM。我现在走在正确的轨道上。
  • @NolanRobidoux :我能够使用在线反汇编程序,他们称之为base address(不是原点,但同样的事情)。当我去拆卸它时,它看起来确实正确。可能您会发现的每个反汇编程序都可以选择更改 VMA/基地址/原点。
  • @NolanRobidoux onlinedisassembler.com/odaweb/Exbuh1Ra/0 是我可以渲染的输出。我最初选择机器架构类型 i386,然后将其更改为 intel 语法并解码为 i8086。然后我必须在第一条指令上右键单击反汇编窗口并选择 data->code 以正确反汇编原始数据。
  • 是的。都摆在那里。超级简单的东西通常会让我绊倒。我从我的 wiki 阅读中知道了 0x100 基数。只是显然不是如何应用它。类似的事情一直在我身上发生。几年前花了几个小时来弄清楚为什么我不能在 Java 和 Erlang 之间编写一个 Diffie Hellman KEX(今天早上刚刚得到 +10;我脑子里很新鲜),因为我只是掩盖了 Java 的 BigInt 文档中的“二进制补码”。