| Get past the idea that you need to be advanced to grok assembly language. Assembly is in a lot of ways easier than a lot of higher-level languages. When I was growing up in the early 90s, a lot of my friends started on x86 assembly as a first language --- and x86 is the most annoying instruction set to learn. The right way to learn this stuff is to dive in. You'll be over your head for a few hours, but you'll get your bearings. There are topics this technique doesn't work great with, but assembly reversing isn't one of them. An additional benefit: assembly is one of those things that you might not use all the time in your career (although I've ended up using it quite a bit), but that will nonetheless illuminate lots of other things about computer science. There's a reason Knuth used it as a language to express algorithms in TAOCP. I can sum up the core idea of assembly for you in just a few sentences: * You're given 8-32 global variables of fixed size to work with, called "registers". * Virtually all computation is expressed in terms of simple operations on registers. * Real programs need many more than 8-32 variables to work with. * What doesn't fit in registers lives in memory. * Memory is accessed either with loads and stores at addresses, as if it were a big array, or through PUSH and POP operations on a stack. * Memory is to an assembly program what the disk is to a Ruby program: you pull things out of memory into variables, do things with them, and eventually put them back into memory. * Control flow is done via GOTOs --- jumps, branches, or calls. * A jump is just an unconditional GOTO. * Most operations on registers, like addition and subtraction, have the side effect of altering status flags, like "the last value computed resulted in zero". There are just a few status flags, and they usually live in a special register. * Branches are just GOTOs that are predicated on a status flag, like, "GOTO this address only if the last arithmetic operation resulted in zero". * A CALL is just an unconditional GOTO that pushes the next address on the stack, so a RET instruction can later pop it off and keep going where the CALL left off. Everything else is just a detail. When working with assembly, a lot of people will just get the programmer's reference manual for the instruction set in a PDF (they're published for free). Here's a short one for X86: http://ref.x86asm.net/coder32.html Here's ARM: http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001m/QR... Here's AVR: http://www.atmel.com/images/atmel-0856-avr-instruction-set-m... Even if you'd never written a line of assembly, if I asked you to express the procedures of a simple Ruby program in assembly and gave you the instruction set reference and those sentences, you would figure out how to get the job done in a couple hours. No monads or linear algebra required! |
The first time I reversed anything was when I was playing a shareware game on my mom's Quadra 650 running Mac OS 7.6.1. I was maybe 12 or 13. I had reached the end of the game's limited demo, and it asked me to enter a code.
I discovered that a program called "Super ResEdit" would open up the game and show me its internal resources. Icons, text, menubars... and also a long column of lines that looked something like "ADD R1, R2, R3" and "CMP R2, R3" and "BNE +0x8".
Anything of the form "B ..." or "BEQ ..." or "BNE ...", when I moved the cursor over it, would develop an arrow pointing to a different line. Aha! "B" stands for "Branch". In that case, "BEQ" stands for "Branch if equal", "BNE" stands for "Branch if Not Equal". It must be that "CMP", which usually preceded one of these lines, stood for "Compare"...
After that it was a matter of finding a section called "do_registration_check", seeing a bunch of arithmetic ("ADD", "MULT"), then a "CMP" followed by "BNE". Apparently if I entered an incorrect code, the "Branch Not Equal" path would be followed. I didn't know about NOPs at the time, since the compiled code didn't have any, but I could change a "BNE" to a "BEQ".
Super big rush! Discovering, on my own, how to take something apart and bend it to my will.