
Editing binaries: easier than it sounds - platz
http://danluu.com/edit-binary/
======
pilif
Tangentially related:

 _> But they couldn’t push the old version into the auto-updater because the
client only accepts updates from higher numbered versions_

This is one of the reasons why I always make my auto-updating routines as dumb
as possible: The only thing the client does is to tell the server its version
and then let the server decide. If it believes there's an update, it sends the
(signed) update. If it doesn't, it 404s.

This way the server (easily modifyable) has full control and there's less
chance for the client (hard to modify, needs to work for any kind of update to
work) to end up in a non-updatable state.

~~~
tfinniga
Putting as much logic as possible into the server component is definitely the
way to go.

I did something similar, I would send the version as well as the md5sum of the
executable.

Aside from being able to tell the 32 and 64-bit versions apart, the other
advantage was that I'd be able to track whether they were running an
executable with the md5sum I shipped, or if it had been hacked. Add that to an
ip geolocation server, and now I've got a map of who is using a legal version
and who is using an illegal version. I even plotted the success and spread of
different cracks over time.. in our case, the Russian cracks usually lagged
the Chinese cracks, but then had a better distribution network. Our auto-
update function would check once a day on startup, based on the same version
string and md5sum of the last check. So, we could see the person creating the
hack.. same IP address, same version string, multiple md5sums, and their final
md5sum would spread.

I also added the demo status and a unique machine id, and that let us answer
questions like "Do paying customers ever install a hacked version?", "Do
people who start with the hacked version ever pay?", "Into what languages
should I translate my software", "How many demo users are in our funnel", "How
long does it take a demo user to convert to paid", etc.

~~~
TeMPOraL
Awesome!

For us curious, could you please tell what answers did you find for those
questions?

Also, I'd love to see that crack spread map, or hear more about it :).

~~~
tfinniga
To answer the questions, at least in our particular case:

\- Do paying customers ever install a hacked version?

Yes, this happened fairly often.. less than 1% of the time, but still often
enough for us to take it into consideration.

There were some silly suggestions about what to do when we detected it was a
cracked version. If there is _any_ chance that it would occur on a paying
customer's computer, you can dismiss the silly suggestions pretty quickly. In
the end we decided to just save out files which were unreadable by end users,
but that we could recover the data from. Our customers had to contact us, and
then we could recover the data and sort out their licensing issues at the same
time. We didn't have any issue with them using a crack to get their job done,
we just wanted to make sure their experience was good.. sometimes the cracks
broke functionality.

Non-paying users could become customers and get their data, but this didn't
really happen very often.. it was enjoyable to read their reactions on the
warez forums though.

\- Do people who start with the hacked version ever pay?

Um, not really, as far as I could tell. IIRC it was 1 or 2 out of tens of
thousands.

You have to be careful not to spend too much time on this stuff.. if you
aren't converting cracked users to paid users, then the time is better spent
just improving the product.

\- Into what languages should I translate my software?

In our case it was Italian, Korean, Japanese, Spanish, German, and French. We
had a lot of Russian and Chinese users, but almost none of them paid, so it's
not worth paying for the translation.

\- How long does it take a demo user to convert to paid

We switched from a time-limited demo (30 days) to a usage-limited demo (25
saves). After using up your saves you could still use the product to learn it,
but just not save or export your work, and if you needed a time-limited demo
or any other kind of trial extension we would provide that for the asking. We
did this because we thought that our target users were very busy, and giving
them one shot to try out the product over 30 days was unreasonable.. it was
more reasonable that they would have a few hours here and there to learn it
and evaluate it.

Anyhow, the data on conversion time did bear out the decision.. we had users
who converted from demo to paid the same day, after 1 week, after 6 months,
etc.

\---

In general, our approach was to encourage people to pay if they're the type of
people that pay for software, and not worry too much about people that don't
pay for software.

Unfortunately I don't have the actual heatmap of legit / cracked users. I do
have a copy of the country by country breakdown, but I'm not sure what date
range it was for.

I do remember that the cracks would come out only a few hours after we
released our software.

For these numbers, legit was a combination of currently in demo, and fully
paid. Anything else was a cracked version. From most total users to least,
here are the top few.

US: 78% legit

China: 17% legit

Korea: 37% legit

Italy: 64% legit

UK: 75% legit

Russian Federation: 18% legit

Germany: 61% legit

Japan: 80% legit

Spain: 71% legit

Turkey: 22% legit

Sweden: 83% legit

Taiwan: 37% legit

Ukraine: 27% legit

Poland: 73% legit

France: 64% legit

Czech Republic: 51% legit

Hong Kong: 17% legit

Canada: 78% legit

Most of this isn't too unexpected. We did have an amazing Polish
trainer/reseller.

Here's some more data. The number of users was quite small in most of these
countries, so it's not a good sample.

Countries with 100% legit copies: Switzerland, UAE, Peru, Vietnam, Mauritius,
Malta, Morocco, Latvia, Venezuela.

Countries with 0% legit copies: Asia/Pacific Region, Bangladesh, Chile, Costa
Rica, Estonia, Kenya, Singapore, Armenia, Kazakhstan, Moldova, Syrian Arab
Republic, Pakistan, Georgia, Lithuania, Indonesia

I think I've got the raw data sitting around somewhere, maybe it would be nice
to put it into a blog post some time. I'd have to get permission though.

------
mbrock
At a previous job we had a pretty serious off-by-one error in a crypto module.
This module was distributed as a binary DLL to dozens of customers. For
various reasons it would have been a costly and inconvenient project to
rebuild it from source and redistribute it. So I located the bug and realized
it could be fixed by just increasing a constant in the binary.

The best part is that the relevant bit pattern turned out to be legible in
ASCII. So this serious bug could be fixed by searching for something like ".,"
and replacing it with ".~". I taught the devops guys to do this in Notepad++.
The DLL could even be reloaded without restarting the server. Problem solved!

When I left the company and wrote a little report about this, the architect
patted me on the back and sighed deeply. With his customary tone of affection
and good cheer, he said "mbrock, you are a horrible, horrible person."

~~~
ColdHawaiian
I don't understand the architects response, was he being sarcastic?

~~~
mbrock
I think he appreciated my willingness to sometimes be a horrible, horrible
person for the sake of the business. :)

------
chinpokomon
In my youth, I learned to recognize conditional JMP instructions by their
opcodes and would bypass copy protection and nag screens all the time with CD
90, or explicit JMPs depending on how the code executed. I probably spent more
time working on the crack than I ever did playing the games I'd patch, but I
have no doubt that the practice is what inspired me to become a developer. It
was so satisfying when I understood how a program worked at such a low level
and I could get into the heads of the creators of those applications and
games.

~~~
userbinator
I remember one of the more esoteric applications of binary patching I had to
do was to get a bunch of DOS utilities available for an older version running
on a newer version, since they had somehow decided to hardcode a versioncheck
in them. I used a text editor in binary mode to do it, entering the bytes
using Alt+nnn on the keypad.

Thanks to that, the sequence 180 48 205 33 is now embedded in my memory, as is
the number 144, and I've acquired the ability to literally read x86 machine
code in ASCII. That's a skill that is probably not much more useful than
memorising digits of pi, but it's fun to see the reactions of experienced
developers when I open some executable in Notepad and start mentally
disassembling it.

I've bypassed a few protections too, but probably have spent more time on
tweaking various software to my liking. Correcting spelling errors in
messages, adjusting UI elements, removing useless messageboxes ("Operation
complete! Click OK to continue."), etc.

~~~
benkillin
That skill is actually very useful if you are researching/developing format
string vulnerability exploits.

There was a presentation I saw where a guy was able to extract a private RSA
key from memory of a novell login screen by using typing in machine code using
alt key combos in the username or password text field, exploiting a format
string vulnerability.

This is the video of that presentation for the interested:
[http://www.youtube.com/watch?v=jv0adeL4x1U](http://www.youtube.com/watch?v=jv0adeL4x1U)

~~~
Bjartr
Here's a more recent version of that same presentation where you can actually
read the screen
[https://www.youtube.com/watch?v=9b_ZWJec95w](https://www.youtube.com/watch?v=9b_ZWJec95w)

------
cperciva
There are some binary edits which are just plain trivial: Editing data which
is embedded into binaries. As an 11 year old, I was annoyed that Civilization
had "Americans" but not "Canadians", so I pulled out a hex editor and
corrected that omission...

~~~
lmm
Of course that's only trivial if the strings are the same length - in my
childhood I broke some programs that way.

~~~
tjgq
Ah, the memories. I had to thrice reinstall DOS on my childhood computer
because of that. I later learned that editing binary files in a text editor
wasn't a very bright idea...

------
taspeotis
Raymond Chen has some interesting articles on patching and hot patching
Windows. Among others:

* [http://blogs.msdn.com/b/oldnewthing/archive/2011/09/21/10214...](http://blogs.msdn.com/b/oldnewthing/archive/2011/09/21/10214405.aspx)

* [http://blogs.msdn.com/b/oldnewthing/archive/2013/01/02/10381...](http://blogs.msdn.com/b/oldnewthing/archive/2013/01/02/10381672.aspx)

This one most closely matches the spirit of the article:

* [http://blogs.msdn.com/b/oldnewthing/archive/2012/11/13/10367...](http://blogs.msdn.com/b/oldnewthing/archive/2012/11/13/10367904.aspx)

~~~
Gracana
The Microsoft Money one is actually linked from Dan Luu's article. Interesting
reads, all of them.

------
anigbrowl
This is worth it just for the link to radare:
[http://www.radare.org/y/?p=features](http://www.radare.org/y/?p=features)

I don't actually program a whole lot and when I do it's usually part of a
reversing effort on something obsolete or buggy or that I can't figure out how
it works (not warez stuff, though). Assembler is enormous fun to dig around in
if you have time on your hands and enjoy puzzle-solving. Another good free
tool if you're into this sort of thing is Ollydbg. :
[http://www.ollydbg.de/](http://www.ollydbg.de/)

------
arbernat
You can do pretty radical modifications of code too if you're willing to move
it somewhere else to get the room to enlarge things. It turns out that almost
all x86 instructions are position independent; there's only a few that are.
Then you jump from the original location to the patch, run the patch, and jump
back.

Gratuitous plug - that was my doctoral research (among other things, hot-
patching in safety checks on a running Apache binary), and I wouldn't mind
seeing it get used for a good purpose. The code's available at
www.dyninst.org.

------
chch
I used to do a something similar to this (though less sophisticated) every
time a new Chrome update came out, changing a single byte in the binary so
that I could restore the [http://](http://) at the front of URLs.

I considered making a website to publish the proper offset to change for each
version, but I got complacent after a while.

~~~
wging
How did you figure out which byte to change?

~~~
chch
I haven't done it in a year or two, so it took me a minute to figure out the
basics again.

The short version is that I crawled through the source of Chromium for a while
until I found the flag that controls it [0].

Then, since FormatUrlType was a uint32, and I assumed the storage of constants
would be close together, I did a little trial and error searching through the
binary in Hex Fiend until I found the value for kFormatUrlOmitAll. Then I
would change this value from a 7 to a 5, which would remove the
kFormatUrlOmitHTTP flag (or sometimes to a 1, to see if I liked trailing
slashes on bare hostnames).

Of course, since Chrome autoupdates, I had to do this every few times I
restarted the browser, until I just got too lazy. :) I can't seem to find the
offset this time, though, so I very well might be missing a step!

[0]
[https://code.google.com/p/chromium/codesearch#chromium/src/n...](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_util.h&sq=package:chromium&dr=C&l=67)
[1]
[https://code.google.com/p/chromium/codesearch#chromium/src/n...](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_util.cc&q=kFormatUrlOmitAll&sq=package:chromium&l=986&type=cs)

------
lunixbochs
I just used IDA for this today (I patched the Bochs bios to skip the 3-second
F12 delay on boot).

There's a handy "Patch program" menu under Edit. It allows you to replace
bytes, assemble code, and apply your changes back to the binary.

~~~
BorisMelnik
wow, what a great idea. too bad my BIOS is basically made by north korea and
isnt hackable.

------
ygra
»If it had occurred to anyone to edit the binary to increment the version
number, they could have pushed out a good update in a minute instead of half
an hour«

Or longer because now you have to patch the signature as well (as unsigned
binaries probably won't be distributed by the updater).

------
tehwebguy
This is cool, and reminds me of a disaster I once wrought upon myself:

Maybe 6 years ago I used TextWrangler to find and replace against a folder. It
was only a few characters being changed but there were loads of instances of
them. In my PHP code it was no biggie but I accidentally overwrote parts of a
Flash FLA (hundreds of instances in the binary) and made a massive piece of a
project for my biggest client at the time worthless.

Totally avoidable, lesson learned!

~~~
Filligree
...revision control? Backups?

~~~
nicholassmith
I think a few of us probably have incidents like this that inspired us to use
source control and/or better backup solutions.

------
callesgg
The problem you now have two identical but not identical versions. I would not
like to be part of a team that does binary edits. Unless there is no other
way.

~~~
anon4
Assuming they just compiled the old version with a bumped version number,
that's exactly what they ended up with. If you compile the same source twice
you get the exact same binary.

~~~
awalton
> If you compile the same source twice you get the exact same binary.

You wish this were true. You really, really wish it were. But it's not always.
Reproducibility is a really tough problem when you support 25+ Linuxes, each
with their own versions of GCC and libc, different compiler flags by default,
etc. There's some work being done to make this "better" like GNU ld's build-id
hashing binary sections so it's easier to tell if they changed, and projects
that stash the compiler's flags in a binary section with -frecord-gcc-
switches/-grecord-gcc-switches. But we've still got a long way to go, at least
in the wonderfully fragmented landscape of Linux software development.

Furthermore, the example in the article is rather specious. Versioning is very
often done by macros and string replacement and not some constant somewhere in
a .section that's easy to just "lemme tweak this" and push a new release. No,
you'd have to go through the entire object file to find any place that version
number is used.

It's not the exceptional case in real world software with multiple supported
releases that you see code like:

    
    
        if (version_number == 2 || version_number == 3) {
          do this thing; 
        } else if (version_number == 4) {
          do that thing instead;
        }
    

or its equivalent with #ifdefs, which the compiler can then fold away in
preprocessing or dead code elimination leaving you with the right chunk for
the product version. Hex editing the binary won't catch this, leaving you with
a broken binary.

tl;dr: rebuild the software if you screwed up.

------
agumonkey
The title reminded to investigate emacs core package bindat (bidirectional
pack/unpack of binary layouts) to generate disassemblers/patchers

[http://www.gnu.org/s/emacs/manual/html_node/elisp/Bindat-
Exa...](http://www.gnu.org/s/emacs/manual/html_node/elisp/Bindat-
Examples.html)

------
codezero
This is always an interesting subject. I enjoyed reading this similar (more
practical) application of binary editing by Russ Cox to patch the Mac OS X
kernel:
[http://research.swtch.com/macpprof](http://research.swtch.com/macpprof)

------
eXpl0it3r
While replacing some text and editing some assembly code in a small
application is kind of easy and fun, changing some logic in a larger
application will require a way better understanding of the code. Basically if
you're unable to attach a debugger to it, you'll have a really hard time.

Not to forget that changing binaries violates in many cases the EULA of the
application. Sure nobody will notice or complain, but it's something to keep
in mind.

------
negamax
nop and jmp were my favorite instructions to break key auths. I miss doing
that.

