我正在使用IDA拆卸Test Drive III。这是1990年的DOS游戏。 * .EXE格式为MZ。 。据我所知,COM可执行文件总是在(PSPseg+2be7)结束后立即加载,因此PSP和exe都适合一个段。 MZ可执行文件呢?应用程序的PSP是否相对于应用程序本身有固定的位置?

换句话说,PSPseg偏移量始终相同吗?在我的DOSBox上,程序执行开始时ES始终是Program Segment Prefix (PSP)base-PSPseg,MZ标头中的CS,是0x22CF,产生ES=DS=0x01FE偏移量CS0(16段,256字节-恰好是PSP的大小)。

如果此偏移量不是固定的,并且PSP和应用程序都只是随机加载到足够大的内存位置中,那么至少它们的地址是否有保证?像这样的PSP地址总是低于应用程序的基地址吗?

#1 楼

DOS没有一个概念可以同时运行多个应用程序,而每个应用程序都可以分配内存。终止后仍驻留的程序无法在其他程序运行时分配更多的内存。因此,内存中没有碎片,也没有“足够大的内存位置”。 DOS使用的内存块的末尾取决于很多因素,但是每当加载程序时,都会在最低可能的位置创建PSP,然后直接在该位置加载程序。因此,是的,您可以使用PSP后面的内存来依赖程序,也可以依赖段寄存器与PSP之间的差值是否恒定。

PSP段本身是不可预测的程序员-例如ansi.sys控制台驱动程序,外部键盘驱动程序,Cdrom驱动程序以及各种驻留程序(有人还记得sidekick吗?)之类的东西可能会增加“ dos块”的大小,从而导致加载程序的PSP地址增加(可用内存减少)。但是只要您不更改DOSBOX的配置,您就应该能够依赖PSP-和段寄存器-程序的每次运行都相同。

#2 楼

从文件加载数据之前,MZ格式的可执行文件还具有CS-0x10处的PSP。

引用Tech Help !,可能是最佳DOS编程参考: EXE格式的程序定义了多个程序段,包括
代码,数据和堆栈段。 EXE文件从
PSP:0100开始加载。


评论


应该说“ DS-0x10”。 MZ CS可能离PSP很远。

–彼得·弗里
2014年8月10日在22:02

感谢Peter,但DS应该指向PSP。我希望我的编辑现在更好。

–伊戈尔·斯科钦斯基♦
2014年8月11日7:50

#3 楼

通常,DOS会在PSP之后立即加载.EXE程序,这对您而言意味着-PSP == 0x0010。但这并不一定是正确的,如果您正在编写此(或任何)DOS可执行文件,则可能会更好地了解这一点。但是,这不是您。相反,在这里,您是一名逆向工程师-或至少尝试着成为一名工程师。因此,最重要的不是在所有情况下对DOS都是正确的,而是对于您正在研究的特定可执行文件,无论对还是错,程序员的想法是正确的。

如果该程序通过将我认为是硬编码的0x2BE7添加到PSPseg来将其一些代码重新定位到它所计算的段,那么程序员很可能会依赖于他的程序基址为PSPseg + 0x0010。当然,更准确地了解0x2BE7的来源可能表明程序员更加谨慎。并不是很长一段时间以来我就对任何DOS代码进行了反向工程,但我记得映射程序的分段(包括其对未初始化数据,堆和堆栈的余量)通常是有用的准备。

由于具有通用性...无论在“可能是最佳的DOS编程参考”中怎么说,DOS程序员都不应该依赖于PSP之后立即加载的程序材料。尽管在实践中绝大多数情况下都是如此,但存在一个例外情况:第二,并非完全在程序员的控制范围内。

e_maxallocIMAGE_DOS_HEADER成员为零时,会出现这种情况。这可以在链接时设置,也可以稍后通过诸如EXEHDR之类的工具进行设置。 DOS将此成员解释为零,以此指示以异常方式将程序安排在DOS找到的用于加载程序的任何内存块中。 PSP像往常一样位于底部,但程序材料应放在程序段中尽可能高的位置。两者之间的空间未初始化。

#4 楼

PSP是一个进程表,它包含有关正在运行的进程(应用程序)的信息,由加载程序创建并填充。加载程序使用EXEHDR信息填充PSP的某些字段,否则填充其他字段。创建PSP后,加载程序将抓取应用程序代码(无论EXEHDR之后到文件末尾,然后在PSP后立即加载。 )分配的内存;段中的PSP偏移始终为0000H-100H。当您的应用程序启动时,DS和ES段指向PSP,您必须先将它们调整为应用程序数据段。段不是固定的,它们是基于可用内存空间定义的,但是段内的偏移量始终是相同的,否则您的应用程序会中断,所有数据和代码都是基于段开头的偏移量来定义(计算)的。

CS在分配内存并加载程序后由加载器填充,IP也由加载器填充,此信息从EXEHDR中提取(应用程序入口点的偏移量(计算得出)由汇编器/编译器在构建目标代码时进行),但其由程序员在汇编中定义,它是在masm中指令END之后的标签集,或者是在c中,是编译器的主要函数offset)设置的标签。