Back in the day I worked for a large computer networking company that had (for the time) really high-speed drivers for their adapter cards. I worked on the adapter card drivers writing code in C and assembler.
One of our drivers emulated the Novell IPX/SPX API on the PC and it worked great. Except for one piece of software which would crash (it was a 3270 emulator). I was task with debugging this problem.
It turned out that an optimization in our code meant that if you sent a packet to yourself it would be never actually go into the network. We'd simply immediately deliver it. The real NE2000 driver would send the packet on the network and then receive it.
This piece of software was using a packet sent to itself as a test of network connectivity and because of the way in which the code was written the packet had to be received with a short delay. Basically, the software called Send_Packet and when that API returned it would clear a flag and then it would hang around and wait for the flag to change.
The flag would be changed inside the ESR (sort of interrupt service routine) registered by the software for receiving packets.
Trouble was our optimization meant that the ESR was called while Send_Packet was executing (i.e. before it returned) and hence the flag was always zero and the software died.
The solution was... to ship our network driver with special code that I wrote that would examine the code of all programs that registered ESR for packet receipt. By examining the ESR routine code I would determine whether this particular piece of software was running and patch it to get around this problem.
(Yes, you did read that right: we shipped a network driver that would patch host software live.)
Wouldn't it have been better to just send the packet to the network if said software was detected? After all, it was supposed to be a network test - hopefully at least you replaced it with another network test?
You might think so but it wasn't possible. This was because of the architecture of our drivers which consisted of a portion running in the host machine and a portion running in the adapter card itself on an on-board processor. When the packet was handed down from the host to the adapter for transmission it was the adapter that made the decision about whether to actually transmit it or not.
We could have added a flag for 'really transmit' this to the hand-off but we were obsessed with speed and memory utilization (this is back in the days of extended memory and all that fun) and so this relatively large change to our code to fix one piece of software was deemed unacceptable.
And yes we did fake the network test because the adapter would give us network status so the software ended up getting the right result.
At a previous employer (which will remain unnamed to protect the guilty), my team once discovered that we didn't have the source code for one of our production systems. Well, we had a version of the source code, but it wouldn't build. The version running in production? It was built on the workstation of a since-departed teammate, and apparently never checked into source control.
Fortunately, the replacement for this system was already in development. Unfortunately, we had to patch the system on two occasions before its replacement was ready. Fortunately we were able to make both fixes by patching the binary - once to change a hard-coded encryption key that was linked in to the executable, and once to change a printf format string that was causing a critical bug in production.
The day we finally launched the replacement system and retired the un-buildable codebase was the biggest relief of my career. (Not least because only the team and our immediate manager were ever told about the problem.)
I once tried to crack Microsoft Reader to extract ebooks from memory.
That was a failure, but one innovation, given that Reader checked the integrity of its code against patching... I simply ran Reader, waited 500 milliseconds, then patched it in memory, after the code that checked!
While reversing WMDRM (the older Windows Media DRM), I was beating my head against the wall trying to get around some anti-debugging tricks they had riddled the codebase with. Eventually, I came up with a trick: insert infinite loops where you want to break.
Any time I wanted to break somewhere, I'd inject an infinite loop and watch for the CPU to redline. Then I'd break in, pause the execution, replace the loop with the original instructions, step through it, put the loop back in, and do whatever I wanted to do. This eventually became an automated "nondebugger", which I've since used in various hostile environments.
It's amazing the random things you'll come up with after a few days of way too little sleep and way too much caffeine.
Great article, it's rare that you see good introductory materials on binary patching (and other reversing-related subjects). If you're interested in learning more, I can't recommend this book enough: http://www.amazon.com/Reversing-Secrets-Engineering-Eldad-Ei...
Of course SoftICE does not have handy "save to executable" function (or at least it did not have it in the 90s when I last looked at it).
In that case you simply write down binary signatures surrounding your patch, open executable with any hex editor, find those signatures and patch. Then do binary diff, save it into CRK file and distribute.
PS. I wonder why this guy copied EDX into ECX instead of just doing PUSHF...
I forgot all about pushf. Anyway, the comments are working. I accidentally misconfigured my nginx to not log the antispam requests (and mistakenly not pass them to php either).
One of our drivers emulated the Novell IPX/SPX API on the PC and it worked great. Except for one piece of software which would crash (it was a 3270 emulator). I was task with debugging this problem.
It turned out that an optimization in our code meant that if you sent a packet to yourself it would be never actually go into the network. We'd simply immediately deliver it. The real NE2000 driver would send the packet on the network and then receive it.
This piece of software was using a packet sent to itself as a test of network connectivity and because of the way in which the code was written the packet had to be received with a short delay. Basically, the software called Send_Packet and when that API returned it would clear a flag and then it would hang around and wait for the flag to change.
The flag would be changed inside the ESR (sort of interrupt service routine) registered by the software for receiving packets.
Trouble was our optimization meant that the ESR was called while Send_Packet was executing (i.e. before it returned) and hence the flag was always zero and the software died.
The solution was... to ship our network driver with special code that I wrote that would examine the code of all programs that registered ESR for packet receipt. By examining the ESR routine code I would determine whether this particular piece of software was running and patch it to get around this problem.
(Yes, you did read that right: we shipped a network driver that would patch host software live.)