Not just writing assembly, rewriting a compiled object file without letting any of the addresses change, without having the source to work with, and presumably with almost no documentation, to patch a program that has been left untouched for almost 20 years.
Those properties come by definition. Addresses don't change because you can't (realistically) change things any much and move things around.
Basically, think of it like this: you have an old book, written in some magic runes and is told that a certain (quite short) paragraph is wrong and can be badly misinterpreted due to poor wording. You know, the magic spell goes kaboom.
You have tools that can easily and painlessly: a) translate the runes into a text that mere mortal can reasonably easily read; b) scrub runes off the page and write any new ones over; c) translate your text into runes. There is a simple correspondence between text length and how many runes it would take. Now, all you need is to write the new text that must be no longer than old one was. Not a trivial task, but not something extraordinary. Just rare, because we don't deal with magic runes those days as familiars take orders and handle all the gory details.
Writing assembly requires a skill. So does reading old assembly code of a particular function and figuring out what it did. That's admirable, but not something unbelievable.
It's just rarer to see those days, but not a lost art or anything like that. Crackmes are still alive. On the game cheat forums such patching (albeit, for a different purposes) was the norm, and probably still is for the games that aren't protected. And many embedded developers have their fights for code size quite often.
It is easy to not let addresses change, because compilers without “-O2+“ do lots of extra stack ops. Documentation is not needed there, because it is overflow fix, it is catchable by debugger and both caller and callee are right in bt. And the fact that this program was not recompiled for 20 years actually adds to the possibility of what was done. Modern compilers are much less forgiving.
Anyway, your points are pretty weak and oh-magic-driven, and I don’t see any reason gp comment to be gray or work to be called stellar. Though of course it was done by asm-skilled person.
I think it's easy in all the superficial churn of frameworks and languages to forget how much depth there is in our field. To me, writing a compiler isn't that big a deal anymore; it's the kind of exercise I might use to try a new language out. But when I was a sophomore in college, even after a few years of computer usage, it would have been magic to me.
It takes a lot of work to get to the point of skill demonstrated in this article... but there's still a lot of skill runway beyond that level of skill, too. It's simultaneously true that this is an impressive amount of talent, and that there are people for whom this would be an entertaining momentary side diversion from their normal job.
I kind of agree with the sentiment. It isn't that crazy.
We do this as a matter of course all the time. Patching a small handful of instructions is pretty easy. You could learn to do it on a week or less if you are a decent programmer.
Do it well? Do it quickly? Do it idiomatically and in a short amount of time.... Takes real skill.
I used to patch games for infinite-lives, or to allow my serial numbers to be accepted. Doing this wasn't hard, as somebody who grew up writing assembly language on 8-bit machines in the 80s.
One fun self-challenge was always to make my modifications as small as possible. e.g. one-byte changes were a lot more impressive than two-byte changes.
It's interesting. I have observed if people learn on an 8 or 16 bit machine, like in Microcorruption, they tend to be able to pick up more complex ISAs much easier. It helps to know the first principles.
It is indeed a lost art. I can count with just one hand the amount of colleagues that I know that are capable of doing this. Also this is not assembly, it is object code.
Disassemblers exist. You can take the binary, generate the assembly code, fix it and then re-compile to find the needed changes. I cracked a few sharewares with OllyDbg this way (just for fun, never distributed), and I'm no "leet coder".
> This is way more tedious that disassembling and reassembling a binary.
It used to be stuff we did for fun.
Back in the day we might not even load the entire program into memory - I remember manually patching disk sectors on the C64 with tools that'd let me disassemble arbitrary content to see if it happened to match code.
I also spent a couple of years programming assembly directly in a "machine code monitor" - an assembler used to assemble/disassemble memory instruction by instruction rather than from a file.
This was something several members of my primary school class would do for entertainment.
The idea that this is particularly difficult just reflect that fewer developers have spent time getting familiar with assembly these days.
We still do! When I added Retroarch to my HTPC I wanted it to use the "ok" and "power" buttons on my remote instead of "enter" and "escape" which are only found on a keyboard. While I did contribute a patch to the Retroarch project, which I tested using a laptop, binary patching was much easier on the Raspberry Pi ARM binaries than figuring out the build system for LibreELEC (the binary patch drops support for enter/escape, so it's literally changing two bytes for the two keycodes).
It stopped being fun for me when I moved to an x86 box, I'm afraid. Though I do get my share of asm thanks to my (very slow moving) Ruby compiler project, it's more painful than fun.
Yes, disassemblers will often write raw bytes directives (e.g. "db 72, 101, 108, 108, 111") if they can't disassemble the instruction, so you can get 1:1 by disassembling and reassembling; but I doubt this patch was done by doing that on the whole binary.
To elaborate, you sketch out the assembly you need, assemble it and literally drop those new bytes in.
Tools like IDA Pro, Binary Ninja, and Hopper make this quite easy. A good hex editor and knowing the file offsets is also fine. This is seen as magic because it is a bit of a lost art, but it turns out to be easy to learn.
Check out "crackmes" if anyone has become interested in this topic of mangling binaries by hand. They are fun and you will get results quickly on the easier challenges.
I wouldn't call it a lost art... Assembly is used many places, even for new projects. But it makes sense that assembly programming might seem impressive (or antiquated) to the HN crowd, which I have an impression is composed of a lot of newly grads, web developers, and comparatively few old hats.