4 ms·
Debugging was just different. You had to get into the mindset of the original developer and understand what he intended and the impact of poking a memory-mapped
by jackhack 9y ago
Debugging was just different. You had to get into the mindset of the original developer and understand what he intended and the impact of poking a memory-mapped location (could cause a graphics page flip, or toggle the speaker, or executing something in ROM). Comments were your friend. Without, yes, it could be a challenge.
But decompiling & debugging wasn't just limited to ASM. I once worked for a shop that lost its original C source code and only had a copy of the executable. (major source code control failure - no backups of the server). They decompiled it and worked from the resultant C code. It was as bad as you can imagine, and enormous amounts of time were spent renaming "variable1" to "customerName", or methods from "sub232" to "CalculateTax()", etc. After a few months the code was sprinkled with meaningful names, but it was still very difficult to read and felt very unnatural, formal, and distorted. It also ran slower than the original when recompiled.
But as for defeating a disassembler, I recall a few strategies stretching back to the late 70s/early 1980s on the Apple ][, when the "disassembler" was a human being rather than a tool. This is probably more appropriately called obfuscation or even copy protection, but it feels related. There were a variety of approaches taken:
* Self-modifying code. This was the most common approach. Code would loop through areas of memory, incrementing/decrementing values by set values or based on an algorithm to produce valid opcodes. At any point in time, much of the code loaded was nonsense, so debugging had to be done in decoded blocks.
* Jump tables (and indexed jump tables with offsets calculated at runtime) so that the code would skip all over the place. This was mostly just an irritation, rather than a hard obfuscation.
* Burying executable code in resources (sounds/images) and related techniques such as code that calculated its hashvalue and used that to self-modify to 'unlock' executable blocks.
*Overlays. Code was loaded on top of unused resources, and resources loaded on top of code.
And while it wasn't a decompiler defeat, per se, changing the timing for the floppy disk drivers which read from non-standard disks would prevent one from simply loading data from disk and decompiling -- only that code that is in memory could be examined. Nybble-copiers were created to defeat this approach.
One or all of these approaches could be combined to produce code that was a nightmare to debug, but ultimately anything that the computer could execute could be decompiled, eventually.
Fun times.
- js2 9y agoFor the Apple ][ there was even a card (the “wildcard”) which would interrupt the CPU and dump the memory to disk along with a special loader, allowing you to reboot from the disk and resume where the CPU left off. I don't think it had any valid use besides defeating copy protection: http://mith.umd.edu/vintage-computers/items/show/11 http://mith.umd.edu/vintage-computers/items/show/11 Oh and I just found this thing called the “Senior PROM” which I’d never heard of before: http://planemo.org/retro/senior-prom-reverse-engineering/ http://planemo.org/retro/senior-prom-reverse-engineering/ Here's some examples of early copy protection techniques: http://www.fadden.com/apple2/cassette-protect.html http://www.fadden.com/apple2/cassette-protect.html
- tekromancr 9y agoThere is a great collection on the internet archive where someone has gone through and unprotected tons of apple][ disks and documented the copy protection. It's pretty good reading, but a little repetitive after a while. https://archive.org/details/apple_ii_library_4am&tab=about https://archive.org/details/apple_ii_library_4am&tab=about