Aug 13

Reapplying the Decal: The practical application of theory

Tag: Code,ProgrammingAdam Wright @ 4:14 pm

We’re on the home stretch now – anyone who’s survived this far is a brave soul indeed and those who make it through today shall be hailed as kings among men (by me anyway). If you’re just joining us, please read the previous articles before you start. Finally, before we begin, make sure you’ve got this archive extracted, and make a copy of the “helloWorld.exe” file called “worldHello.exe”. We’ll be rewriting the program today and we wouldn’t don’t want to break the original in our experiments!

As promised, we’ll start with the actual x86 assembly “big list” of the program, slightly trimmed to show only the information we’re need (If you want the entire assembly listing, here it is). Again, don’t be scared – it’s actually quite easy to understand. You might want to print it out before reading on.

00401000 55 push ebp
00401001 8B EC mov ebp, esp
00401003 E8 18 00 00 00 call 00401020
00401008 E8 33 00 00 00 call 00401040
0040100D E8 4E 00 00 00 call 00401060
00401012 33 C0 xor eax, eax
00401014 5D pop ebp
00401015 C3 ret
00401020 55 push ebp
00401021 8B EC mov ebp, esp
00401023 68 30 20 40 00 push 402030h
00401028 E8 58 00 00 00 call 00401085
0040102D 83 C4 04 add esp, 4
00401030 5D pop ebp
00401031 C3 ret
00401040 55 push ebp
00401041 8B EC mov ebp, esp
00401043 68 38 20 40 00 push 402038h
00401048 E8 38 00 00 00 call 00401085
0040104D 83 C4 04 add esp, 4
00401050 5D pop ebp
00401051 C3 ret

Let’s make some sense of this. Just like in your hex editor, the first column is the address that the line being shown corresponds to in the file. “But”, I hear your ask, “00401000 is way bigger than the size of the file!”. Exceptional observation indeed, if that was you I heard – The number is actually the “base address”, which is pretty much where the program will end up in memory. Don’t worry about this, as today I’ll translate each of these numbers into the file offset for us.

The second part shows the actual representation of the instructions. This is a chunk of the data from the file at the given address. Let’s check this – load “worldHello.exe” in your hex editor, and scroll down until you find the closest row to 0400 (which corresponds to 00401000). As we read along the line we should start seeing the data shown within our assembly listing – and yes indeed, after a long run of “00” up pops “55 8b ec…”, just as expected. Fantastic!

The final 2 columns are exactly like the “program” we ran yesterday – First comes the assembly instruction, then the associated parameters. This is the bit we’re most interested in, as it gives the human readable portion of the assembly (something we can actually understand). Both of these last two columns were created from the data in the second column by the tool used to “disassemble” the “helloWorld.exe” program into the big list.

Now we’ve got our big list, and have some idea about how to read it, let’s start the process of changing it! First, we need to roughly work out what’s going on, based on our new understanding of assembly, so let’s “run” this program in our heads just like yesterday, starting from the top.

  1. push ebp – Well, we’re not sure what an ebp is, but it must refer to some memory somewhere, as it’s getting pushed onto the stack. Let’s ignore it for now, and hope it doesn’t matter too much.
  2. mov ebp, esp – “mov”? We’ve not seen that before, but all it does is move some memory from one block to another, without it going onto the stack. We can ignore this as well.
  3. call 00401020 – Aha, a call! We know what this does. It’s going to go run the instructions located at 00401020
  4. call 00401040 – Hmm, another call straight afterwards, going to a function that’s near the first one.

Woah, let’s stop for a second now and think about what we’ve found. We know we’ve got a program that prints “Hello” and “World” to the screen. We know we want to change that to print “World” and “Hello” instead. What if the printing functions for each word were separate? In this case, we’d expect them to be called straight after one another – which is exactly the behaviour we’ve just noticed in our assembly. If we can see that both the called functions are similar, it’s likely that we’ve found our printing functions.

So, off to the assembly again, and let’s look at the function under address 00401020.


push ebp
mov ebp,esp
push 402030h
call 00401085
add esp, 4
pop ebp
ret

Well, that looks interesting – it’s moving memory around just like the beginning of our big list, but then it’s pushing something right before it’s calling something. Looking over the function at 00401040, it’s virtually identical – the only difference is the memory it’s pushing before it makes the call! Our hypothesis is looking stronger and stronger. What if the function at 00401085 being used in these functions actually does the printing? If so, we’d expect the memory pushed onto the stack to be the data the function needs to do it’s job – i.e. something to print (this is just like yesterday, when the “add” function needed the numbers to add on the stack). The first of our functions is pushing data at 402030 onto the stack, so everyone eagerly go look at address 0830 in the file (0830 corresponds the 402030 address).

[Sound of people tabbing to and from hex editor]

Yes! Amazing! At offset 0830, our file does indeed say “Hello”! We’ve almost certainly found the 2 functions we want, and we’ve seen where they’re used. Going back to the big list, to the site of the 2 calls (00401003), we need to find some method of achieving our goal. As we want to make the program say “World Hello”, and we think we’ve found the two functions that print “Hello” and “World”, the easiest thing to do will be to just swap the two calls around.

The big list shows us that the data for the first call is “E8 18 00 00 00” and the second is “E8 33 00 00 00” – scroll into your file (offset 0403) and find these two blocks of data, one after the other. If you click on the “18”, you’ll be able to type in a new number – enter “33″. Change the “33” in the second block to “18” in a similar vein. Fantastic – we’ve effectively swaped over the two blocks of data, so we should have reversed the calls! Save the file, and let’s give our new program a trial run!

worldHello.exe failing to run

Oh dear, that was impressively destructive. I hope you didn’t opt to send an error report, because we’re going to fix this ourselves!

We’ve two options for finding out what went wrong. We could attach a debugger (a special program that watches the CPU as it executes each instruction, and tells us what the state of the system) – this would certainly help us track down the problem, and if you start doing this on your own you can expect to spend a lot of time inside one. The other option is for me to tell you what happened. Yes, I suppose I could have rigged this so that we choose the right option straight away, but everyone loves an explosion and it serves to show you what happens when you get things wrong!

To expedite things, I’ll explain what mistake we made. We know the “call” instructions that got modified take a parameter of the address they want to call to – We can see that in the assembly listing. The problem arises in that the assembly listing is too smart for it’s own good – it turns out there are lots of different “call” instructions, all behaving slightly differently but doing the same basic job. A single word is not expressive enough to display this data for us; hence the big list shows all “call” instructions as equal. The only way we’ll ferret out exactly what’s happening is to look at that intimidating data in the 2nd column, and understand what it means.

In our case, the call instruction corresponds to the “E8” on the far left of the hex in the second column. This is the instruction number – the actual data your CPU will use to decide where to send the instruction. Intel has kindly provided us with a big manual of all these numbers, and what they mean, which tells us that “E8″ actually refers to “Call near, displacement relative to next instruction”. So, the parameter to our call isn’t actually an address, it’s how far away from us the call should go. It seems we can’t always trust the assembly given to us by tools – it’s being “helpful” and calculating where the call is going for us, rather than showing us what’s strictly happening.

This means we need to work out the “relative offsets” – how far away from each call instruction the function we want to call is. This isn’t too hard because we’re swapping one call instruction 5 bytes forward (the number of bytes of data for the instruction, if you add them up), and one it going 5 bytes backwards. So, what’s was 33 becomes 38 (5 bytes “further away” to the call) and what was 18 because 13 (5 bytes “closer”). So, let’s make this change. The new data for the first call becomes “e8 38” – change the byte just as we did before. The second changes to “e8 13”, make the change in the same way. Save the result, cross fingers and toes and run the program.

worldHello.exe running with modifications!

Being English, this is the point where I quietly nod my head, shake a hand or two and ponder the meaning of life. Other cultures might want to apply different celebratory techniques, because we’ve achieved our goal! We battled through a remarkably complex set of concepts, and emerged victorious and educated – I feel like I should make certificates. I hope everything was reasonably easy to understand, but these are hard ideas to wrap your head around. If you’re stuck anywhere, leave a comment and I’ll see what I can do to help. Remember: there’s never any shame in asking for help, as long as you ask politely and have tried to understand things from the given material.

So, that about wraps up this 4 part series introducing the “memlocs” process. What’s done for Decal is pretty similar to this, albeit much more involved. We don’t “change” the client to test the functionality we want, but we do inject entirely new functions that will call the functions we find when AC is running. If you enjoyed doing this small exercise, then it’s quite possible you’ll be able (with work and research) to find “memlocs” yourself – I’ll post something later about where you can carry on learning this topic in more detail. Even if you hated every moment of it, at least you’ve got a better idea of the general process. My next article will be a less detailed, more accessible view of another part of the Decal update process, so everyone I alienated with this with can come back and join us.

Oh, wait a second – I can’t forget the promised super bonus questions! There are no guaranteed riches or fame, but I can give you mostly anything you like from my L60 character on Thistledown (if AC is your thing) or my L60 Human Mage on Argent Dawn EU (if you’re a Warcraft player). Hold onto your hats, and give these a try!

Bonus question 1: What changes would you make to print “Hello Hello”?

Bonus question 2: What changes would you make to print “Hello Decal”?

Bonus question 3: We know the printing functions were generated from an object in our source C++. Which of the 3 blocks in the given assembly do you think belonged to that object originally?

Bonus question 4: There’s another instruction that your processor understands: “nop”, or “No operation”. It takes no parameters, has instruction number “90” and does absolutely nothing (the CPU skips right over it). Use this instruction to stop the program from waiting for enter before exiting, and explain what you did.

Bonus question 5 (Advanced Extra Credit): The C++ source code consisted of a single object, “HelloWorldPrinter” which had 3 functions “printHello”, “printWorld” and “waitForReturn”. When compiling, I turned off standard library linking, and used libctiny to reduce the size of the result. All compiler optimisations were off, and no debug symbols were generated. Use this and anything else you can glean, produce a single CPP file that will compile to the given program. Ignoring formatting, the closest to my source code wins!

Answers in the comments please and yes, this does mean could in theory copy someone else but as I’ll only take the first “correct” answer for each question, this shouldn’t be a big deal. Results of the quiz (if I get any replies) will appear in a couple of days, along with the project source.

13 Responses to “Reapplying the Decal: The practical application of theory”

  1. Portaren says:

    1. To get “Hello Hello “, where the original hex was:
    E818 0000 00E8 3300 0000 E84E 0000 00, change it to:
    E818 0000 00E8 1300 0000 E84E 0000 00.

    2. To get “Hello Decal “, change the string “World ” around offset 0838, to “Decal “.

    3. The three sections called from the main section:
    00401020, 00401040, and 00401060,
    are likely the three that originally belonged to the object.

    4. To get “Hello World ” without waiting afterward using NOPs, where the hex was:
    E818 0000 00E8 3300 0000 E84E 0000 00, change it to:
    E818 0000 00E8 3300 0000 9090 9090 90.

    5. Using Visual Studio 7.1 and libctiny, and playing with different compiler options, I found that the executable from the following code disassembles to code very close to that produced by the executable provided. The only differences I found occured late in the code, in what looks like the library functions, which I suspect means we have differing libctiny.libs. I did the Wait function this way because libctiny doesn’t have any input functions, and using libc functions produced significantly more code. I hope I’m close and not just the victim of a fluke in my configuration.

    #include
    #include

    // Note: Make sure buffer overrun checking is off,
    // otherwise the compiler adds a bunch of extra stuff

    class
    {
    public:
    static void printHello(void)
    {
    printf(“Hello “);
    }
    static void printWorld(void)
    {
    printf(“World “);
    }
    static void waitForReturn(void)
    {
    struct // Enforce the stack representation in the original
    {
    char foo[32];
    unsigned long bar;
    } x;
    ReadFile(GetStdHandle(STD_INPUT_HANDLE),x.foo,32,&(x.bar),NULL);
    }
    } HelloWorldPrinter;

    void main(void)
    {
    HelloWorldPrinter.printHello();
    HelloWorldPrinter.printWorld();
    HelloWorldPrinter.waitForReturn();
    }

  2. Portaren says:

    Hmm… my includes got lost, the quotes got converted, and of course the browser is ignoring the whitespace. Anyway, the includes were stdio.h and windows.h.

  3. Archgrove - Implicit Definition » Reapplying the Decal: Answers coming soon says:

    [...] As I’ve only had one answer (albeit an excellent one) to the previous set of questions, I’m going to leave posting my solutions for a little while longer. Note that I have no expectations of everyone doing all 5 (or even most people doing any) but if you want to understand the topic, a hands on approach is pretty much mandatory. [...]

  4. Ashida Kim says:

    Ok, maybe I missed something, I have known to be absurdly blind sometimes. What did you use to generate the big list in this article? Was it a decompiler? If so, can you recommend a freeware one?

  5. Long Duk Bill says:

    Great series. I haven’t done any decompiling since TRS-80 Model 4′s were state-of-the-art … ok, I’m dating myself. And the last comment was a good one, too. What decompiler are you using? Hex editors don’t create an Assembly output. It’d be kinda nice to be able to play along with you without having to be spoon fed some vital intel (i.e. the actual assembly code)

    Oh, as for the answers, I did the exact same thing Portaren did for the first 2, came up with the same answer for #3, didn’t play with #4, and my C++ is so rusty for #5 that I figured I’d just be lazy and see who had the best response to date :D (I’m old, I’m allowed :D )

  6. Long Duk Bill says:

    Oh, Portaren, it also didn’t copy the name of your class over, either, in the declaration.

  7. Long Duk Bill says:

    Oh, another fun little thing to do by strictly editing the executable…

    Make the program output “Bite Me World”, using only a hex editor. Not quite as trivial as it sounds. A calculator that does hex math is very useful for this one, btw.

  8. Adam Wright says:

    Thanks for the kind words! I accept the point that I didn’t give any instructions on how to generate the assembly. I did this deliberately, as the only way I can guarantee that people are seeing exactly what I expect is to just give it to them directly. Additionally, the tools I used are only available (as far as I know) from the Microsoft Visual Studio suite, something most people won’t have.

    However, for those who want to replicate exactly what I did to generate the listing, find “dumpbin.exe” in your VS install, with execute it on the “helloWorld.exe” file with “/disasm”. The generated code was truncated and reformatted a touch for clarity in my article, but the output should be close to identical. You can, of course, use any other disassembler (for example, IDA), but the format of the output will likely be different.

    I’ll put of a complete list of tools I used in the “solutions” article.

  9. Portaren says:

    Long Duk Bill, it does certainly look like it lost my class name, but that’s because I’m using an anonymous class, since I only need the one object out of it, HelloWorldPrinter. If you want, you could call it HelloWorldPrinterClass.
    It compiles and runs either way and the executables my compiler gives me are only 2-3 bytes different, and those bytes vary even if I compile the same code again, so I think it’s a datestamp or some such.

  10. Archgrove - Implicit Definition » Reapplying the Decal: The surviving stumble to victory! (The weblog of Adam Wright) says:

    [...] Well, there was a total of 2 received answers to the questions in the last part which, whilst somewhat less than I hoped, just makes it more of an achievement to those that tried. I’m sure lots of you are sitting at home using your solutions as some form of abstract modern art, rather than wasting them on this site, and you’re right to do so! [...]

  11. Long Duk Bill says:

    Ahh, Ok Portaren. I just ran thru it with a cheapie compiler I had laying around, and it compiles and runs just fine. Like I said, my C++ is RUSTY! :)

  12. Jungalist says:

    Well, I tried it out too. I got the first two questions with no trouble but I kind of fell apart after that. Great articles though, I just found them today and am getting nothing done at work because I’ve read them all!

  13. Paul says:

    Hi all,

    If anyone’s interested, the objdump tool from the GNU toolchain can be used to generate assembly:

    objdump -d helloWorld.exe > helloWorld.asm

    Produces quite nicely formatted stuff, too.

    Assuming most of the people here are running in Windows, you can get the GNU tools by installing Cygwin (http://www.cygwin.com/)