【问题标题】:x86 segmentation, DOS, MZ file format, and disassemblingx86 分段、DOS、MZ 文件格式和反汇编
【发布时间】:2014-08-07 16:40:18
【问题描述】:

我正在拆卸“试驾 III”。这是 1990 年的 DOS 游戏。 *.EXE 具有 MZ 格式。 我从未处理过分段或 DOS,所以如果您回答我的一些问题,我将不胜感激。

1) 游戏system requirements提到286 CPU,有保护模式。据我所知,DOS 是 90% 的实模式软件,但有些应用程序可以进入保护模式。我可以确定应用程序仅在实模式下使用 CPU 吗? IOW,是否保证段寄存器包含段的实际偏移量而不是段描述符的索引?

2) 所述系统要求提及 1 MB RAM。如果地址空间的最高 384 KB 是为 MMIO 和 ROM 之类的东西保留的,那么如何访问这么多的 RAM?我听说过 UMB(使用 UMA 中的孔来访问 RAM)和 HMA,但它仍然不允许访问整个 1 MB 的物理 RAM。那么,宝贵的 RAM 是不是因为它的物理地址恰好是为 UMA 保留的而浪费了呢?或者游戏使用了一些拐杖,比如 LIM EMS 或 XMS?

3) 当代码跨越段边界时,CS 会自动递增吗?比如说,IP 达到 0xFFFF,然后呢? CS 是否在执行下一条指令之前切换到下一段? SS也一样。当 SP 一直下降到 0x0000 时会发生什么?

4) 可执行文件的 MZ 标头如下所示:

signature 23117 "0x5a4d" 
bytes_in_last_block 117 
blocks_in_file 270 
num_relocs 0 
header_paragraphs 32 
min_extra_paragraphs 3349 
max_extra_paragraphs 65535 
ss 11422 
sp 128 
checksum 0 
ip 16 
cs 8385 
reloc_table_offset 30 
overlay_number 0 

为什么没有重定位信息?它甚至意味着如何在没有地址修复的情况下运行?还是将其构建为由程序计数器相关指令组成的完全与位置无关的代码?该游戏带有一个作弊实用程序,它也是一个 MZ 可执行文件。尽管要小得多(8448 字节 - 小到可以放在一个段中),但它仍然具有重定位信息:

offset 1 
segment 0 

offset 222 
segment 0 

offset 272 
segment 0 

这允许 IDA 正确反汇编作弊代码。但是游戏EXE什么都没有,虽然它明显有很多远指针。

5) DOS 中是否有“节”之类的东西?我的意思是,数据部分,代码(文本)部分等? MZ 头指向堆栈部分,但它没有关于数据部分的信息。 DOS程序中数据和代码是完全混合的吗?

6) 为什么在 EXE 文件中甚至有一个堆栈部分?它只有零。为什么要浪费磁盘空间而不是仅仅说“从这里开始堆栈”?像 BSS 部分一样吗?

7) MZ 头包含有关 SS 和 CS 初始值的信息。 DS呢?它的初始值是多少?

8) MZ 可执行文件在 exe 数据之后有什么?作弊实用程序在可执行文件的末尾有整整 3507 个字节,看起来像

__exitclean.__exit.__restorezero._abort.DGROUP@.__MMODEL._main._access.
_atexit._close._exit._fclose._fflush._flushall._fopen._freopen._fdopen
._fseek._ftell._printf.__fputc._fputc._fputchar.__FPUTN.__setupio._setvbuf
._tell.__MKNAME._tmpnam._write.__xfclose.__xfflush.___brk.___sbrk._brk._sbrk
.__chmod.__close._ioctl.__IOERROR._isatty._lseek.__LONGTOA._itoa._ultoa.
_ltoa._memcpy._open.__open._strcat._unlink.__VPRINTER.__write._free._malloc
._realloc.__REALCVT.DATASEG@.__Int0Vector.__Int4Vector.__Int5Vector.
__Int6Vector.__C0argc.__C0argv.__C0environ.__envLng.__envseg.__envSize

这是某种调试符号信息吗?

提前感谢您的帮助。

【问题讨论】:

  • 游戏的可执行文件可能会被压缩或以其他方式防止逆向工程。他们本可以使用一个独立于位置的包装器,它自己执行修复,使用一个不在 .EXE 标头中但与它分开的表。我记得玩过那个游戏很多,游戏有不同级别的逆向工程保护并不意外。
  • @KubaOber 谢谢你的回答。游戏的 EXE 看起来并没有以任何方式压缩。它只包含普通的 x86 操作码。至于自定义包装器,我在游戏代码中找不到类似的东西。
  • 好吧,机器代码在整个可执行文件中看起来是否与位置无关?你刚刚回答了#4。
  • @KubaOber 不,它有很多指令,例如call far ptr 18DCh:78Ch
  • 那么你就知道某处有一个包装器,它可以解决修正问题或强制将游戏重新定位到一个固定地址。如果游戏不使用 DOS 访问磁盘文件,它可以完全移除 DOS 并接管,在此过程中获得大量内存。我不记得你是否可以退出游戏回到命令提示符。有些游戏会“一直玩到重启”。

标签: dos disassembly 16-bit memory-segmentation


【解决方案1】:

回复。 1. 不,除非你向自己证明不是这样,否则你无法确定。一个giveaway 将是代码中MOV CR0, ... 的存在。

回复。 2. 虽然营销材料不应与工程规范混淆,但这是有技术原因的。一个 286 CPU 可以寻址超过 1M 的物理地址空间。 RAM 仅在实模式下“浪费”,并且仅在未使用 EMM(或 EMS)驱动程序的情况下。在 286 系统上,超过 640kb 的 RAM 通常被“推高”以从 1088kb 开始。 ISA 和板载外设的内存地址空间以 1:1 的比例映射到 640-1024kb 窗口中。要在实模式下使用 RAM,需要 EMM 或 EMS 驱动程序。在保护模式下,只要您正确设置了段描述符,它就“存在”。

如果游戏确实需要额外的 384kb 内存而不是实模式下可用的 640kb,这强烈表明它要么切换到保护模式,要么需要服务或 EMM 或 EMS 驱动程序。

回复。 3. 我希望我记得。经过反思,我不希望:)其他人请单独编辑或回答。哈,我确实在某个时候知道:)

回复。 4. 你说“[代码] 有很多指令,比如 call far ptr 18DCh:78Ch”。这意味着以下三件事之一:

  • 使用保护模式,地址的段部分是selector into the segment descriptor table

  • 那里有代码可以重新定位这些指令,而 DOS 不必这样做。

  • 那里的代码强制将游戏重新定位到地址空间中的恒定位置。如果游戏不使用 DOS 访问磁盘文件,它可以完全移除 DOS 并接管,在此过程中获得大量内存。我不记得你是否可以退出游戏回到命令提示符。有些游戏会“一直玩到重启”。

回复。 5. .EXE 标头不“指向”任何堆栈,没有您暗示的堆栈部分,就 .EXE 文件而言,不存在节的概念。 SS register 值是obtained by 将加载可执行文件的段与标头中的 SS 值相加。

链接器确实可以在 .EXE 文件中连续排列节,但这些节的属性不包含在 .EXE 标头中。它们通常可以通过检查可执行文件进行逆向工程。

回复。 6. .EXE 头文件中的 SS 和 SP 值不是文件指针。 EXE 文件可能有一部分映射到堆栈,但这完全是可选的。

回复。 7. 这已经是asked and answered here了。

回复。 8. 这看起来像一个调试符号列表。作弊实用程序与留下的调试信息相关联。您可以在那里拥有完全任意的数据 - 通常是各种资源(图形、音乐等)。

【讨论】:

    猜你喜欢
    • 2012-05-08
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 2011-07-08
    • 1970-01-01
    • 2022-08-08
    • 2011-04-28
    相关资源
    最近更新 更多