修补 68K 软件 – SimpleText
Patching 68K Software – SimpleText

原始链接: https://tinkerdifferent.com/threads/patching-68k-software-simpletext.4793/

## SimpleText 窗口大小补丁:逆向工程总结 一个以较小窗口启动SimpleText的请求,引发了一个出乎意料的复杂编程挑战。最初设想为简单的常量覆盖,但该任务需要使用ResEdit和代码编辑器对SimpleText的68k代码进行深度反汇编和修补。 核心问题是避免为显示图片、视频或关于框的窗口进行不必要的调整。直接修改常量被证明不可行,因此需要注入自定义代码来检测文本窗口并替换为所需大小。这涉及到策略性地用跳转到新添加的子例程来覆盖现有代码,小心管理寄存器使用以避免与SimpleText的例程冲突,并处理应用程序内的多个调整点——包括一个由文档加载触发的调整点。 解决方法包括由于全局变量的限制,将临时数据存储在代码*内部*,直接调用系统例程以避免库依赖,以及应对CodeWarrior关于子例程调用和代码放置的怪癖。最终解决方案是添加一个自定义资源以便于窗口大小重新定义,但修补过程导致ResEdit中的反汇编问题。 作者分享这些详细的经验,希望能帮助其他人解决类似的复古软件修改项目。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 修复 68K 软件 – SimpleText (tinkerdifferent.com) 38 分,由 mmoogle 2 小时前发布 | 隐藏 | 过去 | 收藏 | 1 条评论 mjg59 42 分钟前 [–] 这很美妙,但真正的收获应该是,即使你只有二进制文件的专有软件仍然是可变的。计算机运行你想要它运行的代码。我们必须始终维护这一点,并防止通用计算机不再成为默认情况。回复 考虑申请 YC 的 2026 年冬季批次!申请截止日期为 11 月 10 日 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文
Someone asked to have SimpleText open a smaller text window at startup. Initially, I assumed this would be a fairly easy fix by just overwriting a few constant values in SimpleText code. It turned out to be a pain -- but I learned a lot along the way.

You need to have the code editor (from one of the Apple developer CDs) in your ResEdit preference file in order to disassemble code resources within ResEdit. Then, open each 'CODE' resource of SimpleText and search for _SizeWindow (A91D). Or, just skim the code until you see system calls that look like they have something to do with windows. Here is a nice chunk in routine Anon48. A new window is created, then it looks at the main device, looks at the size of the menu bar (MBarHeight), sets the port, and moves and sizes the window.

But, uh oh, earlier in the code it checks what type of window it is opening. A patch is going to need to avoid resizing code for pictures, video, and the about box.

I could not locate any obvious constants to adjust. Instead, I would need to inject a more complicated routine that detects whether it was a text window and substitute a new rectangle for the size. But, you cannot simply insert code, as it would move all subsequent code down, and the jumps (subroutine calls) that cross over that location would now jump to the wrong spots. So, I need to jump out of their code to my own (appended at the end of the code resource) and return.

For example, SimpleText's code to get the size of MBarHeight can easily be performed elsewhere. My routine need only return the MBarHeight in register D0 before returning. That gives me 8 bytes to overwrite with my jump.

Here is my replacement code. It still is only 8 bytes. But, I now jump to my subroutine, check the result, and jump over their resizing code if my routine says it is changing the window size.

In my subroutine, I make sure all the needed information is in registers (which I checked that SimpleText was not using), I call my various functions and then perform any work that was lost from overwriting or jumping over the original code. Specifically, I get the MBarHeight into D0 and set the current port to the window.

Easy! But, later in the code, SimpleText reads the content of whatever document is being opened and once again resizes the window. So, I needed to patch later code as well. How could I determine at that point that a replacement window size was being used? I simply store the result of the first subroutine (see SetRecentResult above) and then check it on later calls.

Where could I store this information? it is not possible to add global variables and the registers are all reused by SimpleText between the first and second routines. Well, you can store a variable (or an entire structure with many variables) within the code itself. Here is my little workaround for CodeWarrior.

A couple of other tricks.

1. The system routine GetHandleSize has some glue code (they intercept the call in a local library before calling the system). I needed this call, but didn't want to add the weight of CodeWarrior's libary. So, I defined the direct call to GetHandleSize (I didn't need the glue fix).

2. You can pass any of the scratch registers (D0-D2, A0-A1, FP0-FP3) to a C function. The way of defining that in CodeWarrior is noted below. You cannot use any other registers. To make debugging easier, I wrote the original subroutine as a true C function, and the register->C function as a wrapper.

3. CodeWarrior does not support BSR for some reason. Use JSR instead. Also, a called routine must be placed before the caller routine in order to generate a short relative JSR rather than absolute address. See my 'RecentResult' example above, where the routines that call RecentResult are placed after it in code.

4. SimpleText stores literals (strings, constants) at the end of the 'CODE' resource. After that is where I placed my code. Unfortunately, this breaks disassembly in ResEdit. Below, do you see 'A9FF'? That's the '_Debugger' trap call. It is follow by the rest of the code, and the MacsBug symbols for "SimpleTextWindowChoicePrep'

I then needed to hand compute the JSR patched in the original SimpleText code to this location at the end of the code resource.

5. To make it easy to redefine window sizes in the future, I added a resource.

The ResEdit definition of this resource is the TMPL. By the way, I have experienced corruption twice with ResEdit 2.1.3. Perhaps it has a bug with templates?

I doubt this information will be useful to most people. However, it may help avoid some frustrating issues for those few people that attempt patching old software.

Attached is the hacked version of SimpleText.

- David

联系我们 contact @ memedata.com