How I tricked myself into cracking my own legacy App — and failed.

Patric Lee Atrott
7 min readMar 7, 2021

--

I jinxed it.

last week, my boss and I were talking about legacy code, technical depth, etc. when I mentioned that I’m proud about an Application I build for a former client, which ran without an incident or production errors for over 4 years.

Yet, one of the most IT-Wisdoms came true once again — never change a running system…

My former client reached out to me a day later, after I had this little conversation with my boss, letting me know that there is a new EU-Regulation in place and we have to modify a little, small function within the application we have not touched for over 4 years… Damnit, I thought… I jinxed it. Once again. (But that’s another story — magic, sparkling sounds) My next thought was: “never touch a running system” and “well, I don’t know how to reproduce the development environment any more… it’s so long ago…”

So, how can I achieve this small feature release without setting up development environment without spending a lot of effort? Binary patching! Yes, let’s try to do some binary patching — identify the sector where the function sits, where it gets its properties from, and then modify it.

By the way, we’re only talking about a String Array that must be added to PopupMenu to choose new values, in the production system.

And as the headline already declares, I failed. But nevertheless, I want to encourage all of you to be open for failure which to overcome. Below you will see the recap of what happened over the following days. (And please note that this all happened outside and in addition to my fulltime-job and on the weekend of the given week)

[Authors Image: simplified release flow, on the things that happen to deliver]

Adding some string to a property in binary code, which can’t be a big deal, right? You just open the executable file in a HEX editor, check the checksums, make some space available in the defined cluster, remove some unused properties which are negligible and are not that important for running the application… right?

That’s what I thought. So I started with that approach. Opened the file in a Hex Editor, identified the cluster where the information that had to be modified sits, added the values, and removed the next property from the code, saved the file.

Good. How can I now test what I changed? I don’t have Windows System around… CrossOver?!, yes CrossOver the commercial Wine came in handy. I created a Windows 10 Bottle, set up a test environment — and started an unmodified version of the App. Yes! It works, I can navigate the app, invoke CPU intensive functions, and so on. Nice!

Then I added the modified to the Wine Bottle and started it:

Boom. Crash. The App cannot be started. Hmm… maybe I was to aspirational. Okay, let’s check what could happen to that issues… what does the error says about that issue?

“Could not find Property FocusRing”

But wait, I did not removed this property… what happened here? I didn’t know at this moment. So, I reverted to the original file state. Next try: what will happen if I just remove or subsidise another string property, hence remove the byte length and add the won space to string I had to modify? Good question, let’s try. I added the values to the destination string, identified the length of bytes. Then scanned the code for obsolete strings which can be removed and found some where I could win some bytes. Okay, let’s do that!

Crash… also did not work… again: the runtime said: could not find property blah blah blah… Well, there must be something around the clustersize which is odd now.

[Authors Image: now it’s time to move on with next approach]

But where can I find the definition of a cluster size? How can I identify the checksums? I started to deep dive. Next, I scanned the binary code for patterns and found one, one that led to the conclusions: I have to find another attempt (given my understanding of binary executables). All those properties, whether I removed them or shrink their value size was already defined there, it also defined where and when, which property to expect…

Stop. I can’t move on, it’s not worth it. Yes, I will learn a lot PEs if I continue, but I cannot help my former client when I spend another week cracking my App.

[Authors Image: Failed Attempt -> let’s move on!]

Two happy hour days were spent on the binary modification attempt (roughly 6 hours) which did not led to a success — so, it was only economical to move on to the next attempt. To setup a development environment which meets the requirements to build and deliver the app as it would be the year 2016. Tough challenge… I don’t have a Windows System to around anymore (but wait we already identified a solution for that — CrossOver) but further more: I don’t have a 32 Bit macOS environment around anymore… my MacBook is running on Big Sur and on macOS you don’t have such thing as a 32 Bit compatibility mode (which is by the way a reasonable thing). But wait once more again! Didn’t I have this old Mac Mini Server from 2011 somewhere around in my Apartment anymore? Yes, I do! So let’s do that setup the dev environment!

[SpongeBob SquarePants Meme]

I felt like a crazy professor in the meantime. Several challenges came across the corner suddenly like, where do I find the last recent published code version? Usually I would say: hey, let’s check our Bitbucket Account — but this time it was different, the code file is binary, hence not version controlled, hence not stored in Bitbucket…

I lost almost a day waiting for a restore… because the only last recent code files were stored in my iCloud Drive (why I don’t like this kind of personal Cloud Storage anymore is another Story, and why it’s not a suitable solution for my purpose) — damn, iCloud is so slow… even until today the complete iCloud was not downloaded (200GB — already 4 days in restore mode) But the important files I could force download, and it only took one night for around 12 Gig. Twelve Gigabyte, for a “Coderepository”?! You might ask, yes and no — the folder structure with the files is that big.

Nevertheless, I could restore the development environment and start to identify the next steps to release a new version — wouldn’t there be one issue: what was the last file I worked on? Two I could identify which I have worked on. One saved with a saved with a newer IDE Version and one with a version from 2012… I decided to go with the newer Version which led to a strange behaviour, when trying to compile and release under a (yes) 64 Bit binary:

[Authors Image: 64 Bit compiled with no code modifications, a graphical disaster]

Reason for 64 Bit incompatibility: I wrote the GUI Kit Library on my own, to better Support Multi-Platform, and it’s based on several 32Bit instructions, and obviously 64 Bit float with 32 Bit instructions seems to be not going well.

Back to the topic: the newer Version seemed not to be the go-to one, but why did it exist either way? Well, because I am stupid. I released a Version in 2016 which worked well and wanted to update to 64 Bit then soon. So, I took the file and migrated it — without saving a compatibility version…

So, I had to go back to the other last file version. But what if that version is missing crucial instructions and functions, which I can’t remember anymore?

When I started comparing both version files I was overwhelmed, 6361 differences… damnit… How could I made so many changes without documentation? Well, I did not! All but 4 changes where from migrating to a newer IDE Version. After Identifying the 4 changes and merging them together. I was able to build and deliver the release version I was so desperate to deliver. And it worked, very well. Yes!

Now I can finally add the new requirement which was originally requested.

What now? What did I learn during this challenge?

First of all: that I write damn good code that still runs for over four years without incidents, errors, or complications — which can be easily modified.

If I wasn’t that stupid for not using version control mechanisms.

That is the second thing: All files are now finally migrated to Bitbucket and the complete Development Environment lives as migratable Image ready for deployment.

Third thing: always try to challenge yourself. I knew some things around binary patching already, but never ever have I tried to crack my own applications. Yet, I failed — but so what… :D

Most of all: it was fun! Really fun!

No animals were harmed during the writing process.

Cheers //Patric

Disclaimer: This article is an opinion and was not sponsored. All statements may depend on facts but are opinions and should be perceived as such. Also, I don’t use affiliate links.

--

--

Patric Lee Atrott

Manager Employee Tech @HeinekenGermany // Agile Coach // It's all about ONES and ZEROS; so lean back and relax. // Cheers!