Reversing MacOSX

Embed Size (px)

Citation preview

  • 8/11/2019 Reversing MacOSX

    1/27

    Universe's best and legal Mac OS X reversing tutorial for newbies (or maybe not!)------------------------------------------------------------------------------(c) 2011 Fractal Guru (reverse AT put.as , http://reverse.put.as)

    Target: Macserialjunkie.com Cracking Challenge 09 #1Tools used: OTX, GDB, 0xED, gccPlatform: Mac OS X Leopard 10.6.5 @ Intel x86Document version: 0.1 (12/02/2011)

    Index:0 - Introduction1 - Building our toolkit2 - How to use our tools2.1 - OTX2.2 - GDB2.3 - Putting otx and gdb together3 - Reversing and cracking Challenge #13.0 - Introduction and workflow3.1 - Patching the binary3.2 - Fishing a valid serial number3.3 - Keygen4 - Conclusion

    0 - Introduction----------------Update from the original version:

    Reversing and breaking protections is a great hobby and fantastic knowledge to possess.The problem is that many abuse this and want to profit from it. I really don't like not sharingknowledge because sharing also allows me to progress, seeking new challenges and learning new things.I really hope that you make good use of this information and do not share your cracks with the world,especially in MSJ that is full of idiots just wanting to rip off others work. Do

    n't do that please.Don't make me regret once again releasing knowledge that may ease piracy!Enjoy the process, learn, get frustrated, and buy the apps if you really use them in your day to day.This tutorial is still based on 32bit binaries.

    Have fun,fG!

    ----

    One of the most difficult tasks is to write a tutorial for beginners. It's not an easy task

    so here's an attempt to create one that can launch people with some basic knowledge into theworld of reverse engineering (I consider cracking a subset of reverse engineering, and a veryuseful one as a learning platform).It's assumed you have basic x86 assembly knowledge (already too many good tutorials about this!).Some URLs:http://www.woodmann.com/crackz/Getstart.htmhttp://www.uc-forum.com/forum/programming-beginners/63947-reverse-engineering-be

  • 8/11/2019 Reversing MacOSX

    2/27

    ginners-guide-x86-assembly-and-debugging-windows-apps.htmlhttp://en.wikipedia.org/wiki/Assembly_language

    The term "function" will be used alot. If you know Objective-C or C++, you knowit's not entirelycorrect to use it. Method would be more correct in this context. But some partsof this tutorialcan be used to reverse other languages where the term function is correct. It shouldn't be a bigdeal for you to handle.

    A word of caution: reversing/cracking is about exploring and thinking. You should get used tothink and explore problems and find solutions for them. These days, Google and other searchengines are your main friend and they can make your task much easier ! Get usedto search, thinkand explore ! That's the beauty of Reverse Engineering, diving into the unknown!

    And now, let's start the fun !fG!

    1 - Building our toolkit

    --------------------------The first step is to build our reversing toolkit.For me, two tools are essential, a disassembler and a debugger (especially thisone!).There are three available disassemblers and two debuggers. In disassemblers we haveIDA Pro, Otool and OTX. IDA is the most famous and powerful but it's paid (there is a demoversion available (HexRays released a native OS X demo version!), and a warez version is around ofcourse) and it's expensive. If you are serious to RE field and can buy it, do it !

    If your company can buy it, ask them to buy it. It's worth the money!An excellent book about IDA is "The IDA Pro Book: The Unofficial Guide to the World's Most Popular Disassembler"by Chris Eagle. Buy it if you can (it's not that expensive and author deserves it!).The other two options are technically just one, since OTX is a frontend for Otool.OTX is available at: http://otx.osxninja.com/Otool is part of XCode, available at: http://developer.apple.com/ (open an account, it's free!)GDB is part of XCode, so you should download both. The available debuggers are GDB and IDA (the debugger is integrated with the dis

    assembler).GDB is free and part of XCode. This tutorial will use GDB since it's faster to use (because IDA uses remotedebugging, meaning you will need two machines to debug) and it's capable to do everything we needfor this tutorial and any future uses you may have.

    To make GDB even more easier to use, you should grab gdbinit. This is a script for GDB that willenhance it's output and has macros to make our work easier and faster.

  • 8/11/2019 Reversing MacOSX

    3/27

    Grab my modified version here: http://reverse.put.as/wp-content/uploads/2010/04/gdbinit73

    To install gdbinit, you will need to copy it into your home folder with the name ".gdbinit".

    For example, if you have downloaded the file gdbinit73 into your download folders, you can installit using Terminal.app with the following command:cp ~/Downloads/gdbinit73 ~/.gdbinit

    ~ in Unix means your home folder.

    There is a bug in Apple GDB version. You can read about it here: http://reverse.put.as/2008/11/28/apples-gdb-bug/It's annoying and not a big obstacle to our work, and it's useful to fix it.You might also want to give a look at http://reverse.put.as/2009/08/26/gdb-patches/ , which features other patches.

    The next tool is an Hex Editor. I use 0xEd, available at http://www.suavetech.com/0xed/0xed.html.Hex-Fiend is another good alternative (http://ridiculousfish.com/hexfiend/)

    You should be able to install everything without any problem.

    To resume, our basic reversing toolkit is composed of gdb, OTX/otool/IDA and 0xED/Hex-Fiend.

    2 - How to use our tools------------------------

    2.0 - Updating OTX------------------

    The binary version of OTX doesn't support 64bit binaries, so you should download the version from theSVN repository. The information is available here: http://otx.osxninja.com/subin

    fo.htmlYou will need XCode to compile the project.

    2.1 - OTX---------

    Run OTX and you will get the program window. We need to open the binary file wewant to disassemble.Open a Terminal.app windows (yes I really love Terminal, some things are done faster and better thru the command line) andgo to the folder where you have the Cracking Challenge #1 application.List all available files with "ls" command.You should see a folder named Challenge #1.app. This is our target.

    Mac OS X programs have a nice program structure, where everything (almost) is contained into a single folder.Using Challenge #1.app as an example, we have the following structure inside it:Challenge\ #1.app/Contents/Then we have the following folders:Info.plist MacOS PkgInfo Resources

    You can find the main binary inside the MacOS folder. This is where we should start.Frameworks folder (not present in this binary) might have interesting binaries t

  • 8/11/2019 Reversing MacOSX

    4/27

    o disassemble becausesome protections can reside there instead in the main binary.Listing the MacOS folder gives us:$ ls MacOS/Challenge #1

    Challenge #1 is the binary we want to disassemble. The full path is:Challenge\ #1.app/Contents/MacOS/Challenge #1

    Some information from the binary can be extracted with the "file" command or otool.To see if this is a fat binary (contains more than 1 architecture), you can usethe following command:$ file Challenge\ #1.app/Contents/MacOS/Challenge\ #1Challenge #1.app/Contents/MacOS/Challenge #1: Mach-O universal binary with 2 architecturesChallenge #1.app/Contents/MacOS/Challenge #1 (for architecture i386): Mach-O executable i386Challenge #1.app/Contents/MacOS/Challenge #1 (for architecture ppc): Mach-O executable ppc

    The equivalent otool command is:$ otool -h Challenge\ #1.app/Contents/MacOS/Challenge\ #1Challenge #1.app/Contents/MacOS/Challenge #1 (architecture i386):

    Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags 0xfeedface 7 3 0x00 2 19 2356 0x00000085Challenge #1.app/Contents/MacOS/Challenge #1 (architecture ppc):Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags 0xfeedface 18 0 0x00 2 17 2412 0x00000085

    So this binary contains two architectures, x86 32 bits and PowerPC.

    Let's try to disassemble the x86 version.Select Open File in OTX and select that binary. You should select x86 as processor (it's the default).

    You might change the output name or just leave the default. Click Save and select where to save (usuallyDesktop or select one folder dedicated to your reversing project to have thingsorganized).If you can also use the otx command line version (I have installed mine at /usr/local/bin).I usually use the following command "otx Challenge #1 >dump.txt".

    And voila, you have disassembled your first binary. Very simple ! The output file is the disassembled listing of theselected binary, and it will be our main guide into reversing the target.

    2.2 - GDB

    ---------Gdb is a very powerful debugger although not easy and not intuitive as Windows equivalents like OllyDbgor Softice (well, Softice as also text only).Nevertheless you can master it and do everything you should need for your RE projects.Let's give it a shot and introduce you the world of GDB !

    Just a little note on the commands to be used:

  • 8/11/2019 Reversing MacOSX

    5/27

    1) Commands issued inside gdb will always use the following prompt: gdb$2) Commands issued in a Terminal.app shell will always use the following prompt: shell$

    To learn gdb we are going to use a simpler target so we can understand the basic commands.You will need to compile the following program example.c:------------------- CUT HERE -----------------#include

    main(int argc, char *argv[]){ printf("Hello GDB!\n"); printf("Argument is: %s\n", argv[1]);}------------------- CUT HERE -----------------Save this source code somewhere and compile it with (if you have called it example.c, else modify the name):$ gcc -arch i386 -o example example.c

    Note:The -arch i386 option is required to compile the binary in 32bits instead of the default 64bits in Snow Leopard.

    This small program will print 2 lines, where the second prints the argument from the command line.Example:$ ./example TestHello GDB!Argument is: Test

    GDB runs from the command line, so you will need to open a Terminal.App (at this moment you should alreadyhave a Terminal.app shortcut into your Dock hehehe). To start gdb, just type "gdb" at the prompt and press enter.You should get something like this (date should be different since this one wascompiled by me on January):

    GNU gdb 6.3.50-20050815 (Apple version gdb-768) (Fri Jan 23 17:22:29 UTC 2009)Copyright 2004 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "i386-apple-darwin".gdb$

    To make sure gdbinit is installed correctly, type "help user". You should get alist of available commands,the ones created by gdbinit script.

    There are two different ways to debug a program, one is to attach to a version already running and the other one tostart the program from gdb.To attach you will need the PID (process ID) for your target. You can find it by issuing a "ps aux" command(or in Activity Monitor). The PID is the number in the second column. After youhave the PID, you use the"attach " gdb command.To start the program from gdb, you can use the "exec-file " (this is the best way to

  • 8/11/2019 Reversing MacOSX

    6/27

    overcome the gdb bug described earlier, if you don't have a patched version).If you need to set parameters to the executable (usually not needed for our targets), you can use "set args" commandor set the arguments when you start the program with "run" command.

    Practical example:To start debugging our example code, open a command prompt and then type the following commands:$gdb(gdb is loaded)gdb$ exec-file "PATH/example"(substitute PATH for the full path where our example binary is)

    or

    $cd "PATH"(substitute PATH for the full path where our example binary is)$gdb(gdb is loaded)gdb$ exec-file ./example

    In the first example we are using the full path to our binary, in the second example we change into the correct directoryand just point to the binary. It's a matter of personal taste (you can use TAB c

    ompletation inside gdb!).The basic commands we need are related to breakpoints, stepping, change flags or memory, dump/evaluate memory locations.

    What is a breakpoint ?From Wikipedia (http://en.wikipedia.org/wiki/Breakpoint):"A breakpoint, in software development, is an intentional stopping or pausing place in a program, put in place for debugging purposes.More generally, a breakpoint is a means of acquiring knowledge about a program during its execution. During the interruption, theprogrammer inspects the test environment (logs, memory, files, etc.) to find out whether the program functions as expected.

    In practice, a breakpoint consists of one or more conditions that determine when a program's execution should be interrupted."

    The breakpoint related commands interesting to us are:1) bp/b (set a breakpoint)

    You can set a breakpoint on a memory location (most used) or in a symbol (if GDB knows about it).For a memory breakpoint you just need to use the memory location where you wantthe program to stop.Example:gdb$ bp *0x1234

    This will set a breakpoint on memory location 0x1234 (you need to use the * before the address). You should have guessed that 0x is theformat for hexadecimal number. If program execution reaches that memory location, program execution will be interrupted and you willget back to gdb prompt!

    Setting a breakpoint on a symbol is equivalent to use a name instead a memory location. Usually it's a function from a library or someother symbol that GDB can solve.

  • 8/11/2019 Reversing MacOSX

    7/27

    An example is:gdb$bp [NSControl stringValue]

    This means whenever the program calls the stringValue function gdb will halt it's execution and return control to us. This function canallow you to break on text input routines, so you can for example fish a valid serial.

    2) bpl (list all breakpoints)This command will list all breakpoints active or inactive.Example:gdb$ bplNum Type Disp Enb Address What1 breakpoint keep y 0x00001f44 2 breakpoint keep n 0x00001f46

    3) bpd/bpe (disable/enable a breakpoint)This will enable or disable a breakpoint.You should use the Num column from bpl output to select which one to enable or disable.Example:gdb$ bpd 1gdb$ bplNum Type Disp Enb Address What

    1 breakpoint keep n 0x00001f44

  • 8/11/2019 Reversing MacOSX

    8/27

    nt to skip over calls or subroutines).These should be enough for your reversing efforts.

    Step commands interesting to us are (this is just a dump of help from gdb, should be enough):1) nextgdb$ help nextStep program, proceeding through subroutine calls.Like the "step" command as long as subroutine calls do not happen;when they do, the call is treated as one instruction.Argument N means do this N times (or till program stops for another reason).

    2) nextigdb$ help nextiStep one instruction, but proceed through subroutine calls.Argument N means do this N times (or till program stops for another reason).

    3) stepgdb$ help stepStep program until it reaches a different source line.Argument N means do this N times (or till program stops for another reason).

    4) stepigdb$ help stepi

    Step one instruction exactly.Argument N means do this N times (or till program stops for another reason).

    5) stepogdb$ help stepoStep over calls (interesting to bypass the ones to msgSend)This function will set a temporary breakpoint on next instruction after the call so the call will be bypassedYou can safely use it instead nexti or n since it will single step code if it'snot a call instruction(unless you want to go into the call function)

    Try to play with these step commands and see what are the differences between th

    em. Like I said,nexti and stepo should be enough!

    The dump/evaluate commands will allow you to dump the contents of memory, cpu registers, variables,pointers, etc.

    Dump/evaluate commands are:1) xgdb$ help xExamine memory: x/FMT ADDRESS.ADDRESS is an expression for the memory address to examine.FMT is a repeat count followed by a format letter and a size letter.

    Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal), t(binary), f(float), a(address), i(instruction), c(char) and s(string), T(OSType).Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).The specified number of objects of the specified size are printedaccording to the format.

    Defaults for format and size letters are those previously used.Default count is 1. Default address is following last thing printedwith this command or "print".

  • 8/11/2019 Reversing MacOSX

    9/27

    "x" will allow you to examine memory addresses and registers. It allows you to use formats for the output (something like printf).Usually you will want to use the "x" format (hexadecimal) and "s" format (string).For example, to dump EAX register contents in hexadecimal you would use gdb$ x/x $eaxCheck this live example, using our example.c code:gdb$0x00001fb9 in main ()--------------------------------------------------------------------------[regs] EAX: 00001FE1 EBX: 00001FB2 ECX: BFFFF848 EDX: 00000000 o d I t S z a p c

    ESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FB9 CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F[001F:BFFFF810]----------------------------------------------------------[stack]BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 [email protected] : 00 00 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........

  • 8/11/2019 Reversing MacOSX

    10/27

    In gdb:gdb $ x/s $eax0x30a9c0: "?c??"gdb $ po $eaxNSBundle (loaded)

    You can see the object where eax is pointing too. Much better than the first x/s $eax

    Change flags or memory commands are:1) cfX, where X can be a,c,d,i,o,p,s,t,z,sAll the cfX commands are from gdbinit. These will allow you to change the cpu register flags (they will invert the current flag state).For example, the JE (jump if equal) assembler instruction, will be followed (meaning the code will jump to the new location) only if the Zero flag(ZF or Z) is equal to 1. If the next instruction to be executed is a JE and theZero flag is equal to 0, there will be no jump. But if you want toeasily force the jump, then you just need to modify the Zero Flag and make it equal to one. You can simply do this by using the cfz command, likegdb$ cfzThis would change the value for ZF from 0 to 1. Or maybe you don't want the jump to be followed (ZF=1) and so you issue cfz to reverse ZF to 0.The different cfX commands are:

    cfa -- Change Auxiliary Carry Flagcfc -- Change Carry Flagcfd -- Change Direction Flagcfi -- Change Interrupt Flagcfo -- Change Overflow Flagcfp -- Change Parity Flagcfs -- Change Sign Flagcft -- Change Trap Flagcfz -- Change Zero Flag

    2) setThe set command has many available subcommands. We are interested in changing memory contents and/or registers contents.

    To change memory location the syntax is:gdb$ set *address = newvalue , where address is in the usual hexadecimal format.The memory location can be program code (if you want for example to live patch the program) or anyother memory location (for example an address holding a variable).

    If you want to change a register content, for example EAX, the syntax is:gdb$ set $eax = newvalue

    You can use complex expressions with set, for example type casting. For exampleif you want to write a single byte you could use:gdb$ set $eax = (char) 0x12345gdb$ print $eax

    $3 = 0x45gdb$ set $eax = (int) 0x12345gdb$ print $eax$4 = 0x12345

    Do you understand what happened with this example ? Think about it (should be easy to understand!).

    2.3 - Putting otx and gdb together----------------------------------

  • 8/11/2019 Reversing MacOSX

    11/27

    Let's play a little bit with gdb so you can watch a debugging session.Disassemble the example binary with otx. You should have an output more or likethis (I have added linenumbers for easy reference here!):md5: 27cc7b61ed3322057d52b6b014d589e6

    (__TEXT,__text) section

    (Uninteresting code here for our purposes, we are just interested in the main function)

    _main:1: +0 00001fa6 55 pushl %ebp2: +1 00001fa7 89e5 movl %esp,%ebp3: +3 00001fa9 53 pushl %ebx4: +4 00001faa 83ec14 subl $0x14,%esp5: +7 00001fad e800000000 calll 0x00001fb26: +12 00001fb2 5b popl %ebx7: +13 00001fb3 8d832f000000 leal 0x0000002f(%ebx),%eax

    Hello GDB!8: +19 00001fb9 890424 movl %eax,(%esp)9: +22 00001fbc e849100000 calll 0x0000300a

    _puts

    10: +27 00001fc1 8b450c movl 0x0c(%ebp),%eax11: +30 00001fc4 83c004 addl $0x04,%eax12: +33 00001fc7 8b00 movl (%eax),%eax13: +35 00001fc9 89442404 movl %eax,0x04(%esp)14: +39 00001fcd 8d833a000000 leal 0x0000003a(%ebx),%eax

    Argument is: %s\n15: +45 00001fd3 890424 movl %eax,(%esp)16: +48 00001fd6 e82a100000 calll 0x00003005

    _printf17: +53 00001fdb 83c414 addl $0x14,%esp18: +56 00001fde 5b popl %ebx19: +57 00001fdf c9 leave20: +58 00001fe0 c3 ret

    Remember that our source version looks like:main(int argc, char *argv[]){ printf("Hello GDB!\n"); printf("Argument is: %s\n", argv[1]);}

    You can easily see that the compiler used "puts" for our first printf and used printf for our second.This was a compiler optimization. Compilers usually optimized your source code and use the best optionsavailable to make your code shorter and faster.

    Since our first printf doesn't have any format string being used, it can be replaced by a shorter andfaster function at compiler level, puts, and still do what we wanted in our source code, to print asimple "Hello GDB!" message.

    Let's start debugging our little program. Open gdb and start our example program.shell$ gdbGNU gdb 6.3.50-20050815 (Apple version gdb-962) (Sat Jul 26 08:14:40 UTC 2008)

  • 8/11/2019 Reversing MacOSX

    12/27

    Copyright 2004 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "i386-apple-darwin".gdb$ exec-file ./exampleReading symbols for shared libraries ... donegdb$

    If you type the run command, our program will run and exit, since we haven't set any breakpoint yet.Let's give it a try:gdb$ runReading symbols for shared libraries .++. doneHello GDB!Argument is: (null)

    Program exited with code 024.--------------------------------------------------------------------------[regs] EAX:Error while running hook_stop:No registers.gdb$

    You can easily see our messages printed.Let's try running our program with an argument:gdb$ run TESTINGHello GDB!Argument is: TESTING

    Program exited with code 025.--------------------------------------------------------------------------[regs] EAX:Error while running hook_stop:No registers.gdb$

    Now let's set our first breakpoint. We want to breakpoint the program before the

    first message "Hello GDB!"is printed. We already know that the function responsible to print that first message is "puts", andyou can find the call to this function at line 9. Let's explain this line contents:

    9: +22 : local offset, meaning the offset inside this function (it's not interesting to us and you can configure otx to remove this)00001fbc : code address (hexadecimal format), this is the addresswe are going to use for our breakpoint(s)e849100000 : opcodes, these are the bytes your cpu will read and for

    m your instructions (and the ones we can modify to patch the code)calll 0x0000300a : this is the assembly mnemonic correspondent to the previous opcode bytes

    _puts : this is additional information that otx was able to identify, in this case

    it identified we are going to call the "puts" function Hopefully you have understood otx output. So if we want to break on line 9, we should use memory

  • 8/11/2019 Reversing MacOSX

    13/27

    address 0x1fbc. To be honest, since we have the source code, we could use source file line referenceto create the breakpoint but since we usually don't have source for our targets, this will not be explored.

    Set the breakpoint:gdb$ bp *0x1fbcBreakpoint 1 at 0x1fbcgdb$

    And list:gdb$ bplNum Type Disp Enb Address What1 breakpoint keep y 0x00001fbc gdb$

    Our first breakpoint is set, we can run again our program (you should already have noted that we canrun again and again the program after we have loaded it into gdb).

    Let's go...gdb$ run

    Breakpoint 1, 0x00001fbc in main ()

    --------------------------------------------------------------------------[regs] EAX: 00001FE1 EBX: 00001FB2 ECX: BFFFF848 EDX: 00000000 o d I t S z a p cESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FBC

    CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F[001F:BFFFF810]----------------------------------------------------------[stack]BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 [email protected] : E1 1F 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........

  • 8/11/2019 Reversing MacOSX

    14/27

    These are due to otx using AT&T syntax and gdb is configured for Intel syntax. You can modify gdb touse AT&T syntax if you aren't comfortable with different syntaxes. Refer tohttp://www.redhat.com/docs/manuals/enterprise/RHEL-3-Manual/gnu-assembler/i386-syntax.html if youare interested in understanding differences between the two.

    At this moment, you can do various operations. For example, you can dump the contents of EAX registeror any other memory location. Or you can step the code to understand it, or simply let the programcontinue running without any further interference.

    If you use "c" or "continue" commands, program will continue running and eventually end. Let's try.

    gdb$ cHello GDB!Argument is: (null)

    Program exited with code 024.--------------------------------------------------------------------------[regs] EAX:Error while running hook_stop:No registers.

    gdb$Since our breakpoint is still set, we can run the program again and it will stop again at the same place. Try it...Assuming you did tried, we are back to our breakpoint. We want to follow and understand the code, sowe are going to step each line of code.Since the next instruction to be executed is a call, you know we can step over it (meaning we don'twant to analyse what "puts" function will do) or we can step into it (meaning we want to analysewhat "puts" is going to do).

    For this example, we are not interested in understanding how "puts" work (sincewe already know itwill just print characters) and just want it to be executed.We can use either "n", "ni", "nexti", "stepo" gdb commands. If you use "stepi" you will get inside"puts" function. The safest bet is to use "stepo" if you want to skip over calls.

    Let's try...gdb$ stepoBreakpoint 3 at 0x1fc1

  • 8/11/2019 Reversing MacOSX

    15/27

    BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 [email protected] : E1 1F 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........

  • 8/11/2019 Reversing MacOSX

    16/27

    ment is: %s\n" and argv[1].You should already know that arguments are passed into the stack (ESP) in reverse order, from last to first.So this first mov instruction is moving the second argument into the stack and the second mov is movingthe first argument.

    You should be able to identify that in this case the was no argument to "run" command since EAX is empty.If you have used a parameter (or set args command) EAX would hold it's contents. Try it ! When you stopthere, use the "x" command to dump EAX contents, like this:(I used run TESTING)gdb$ x/s $eax0xbffff923: "TESTING"

    You can step to line 15 (0x1fd3 address) and dump again the contents of EAX. You should see the firstargument to printf function.

    And that's it ! The basics are covered. You should now know how to set breakpoints, step code anddump memory/register contents.

    3 - Reversing and cracking Challenge #1---------------------------------------

    3.0 - Introduction and workflow-------------------------------

    The first thing to do is reconnaissance. We need to understand what are the program limits and whatmessages (if any!) are being displayed about those limits.If we have an error message like "Bad serial", "Trial is expired" or something like this, the nextstep is to check if this message is present in the program binaries in plain tex

    t, which can give usfast clues where we should start our work.

    The best tool for this job is "grep". If you have Unix experience you should already know it, elseyou are about to be introduced.We want to grep all files belonging to our application. Best way is like this:

    shell$ cd Challenge\ #1.app/Contents/shell$ grep -r -i "message" *(-r means recursive and -i case insensitive)

    When you start Challen #1 for the first time you have a message telling you abou

    t the goals of this crackme.Continue and insert a random name and a random serial. You get an error message:"The name and serial number combination you entered is incorrect."Try to search for that one...There is one hit at "Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib".

    shell$ grep -r -i "you entered is incorrect" *Binary file Challenge #1.app/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib matches

  • 8/11/2019 Reversing MacOSX

    17/27

    This means that there are no direct references in the main binary to the string, so we need touse other methods.

    Another classic way is to open the disassembly listing and search for methods with interesting names.If you browse the disassembly for this challenge, you will find an interesting string "isRegistered".Unfortunately, many developers for OS X use names like this for their registration/protection code,so it's very easy to track them.

    The interesting place where you find this is here:-(void)[Level1 applicationDidFinishLaunching:] +0 0000251e 55 pushl %ebp +1 0000251f 89e5 movl %esp,%ebp +3 00002521 53 pushl %ebx +4 00002522 83ec24 subl $0x24,%esp +7 00002525 8b5d08 movl 0x08(%ebp),%ebx +10 00002528 a110400000 movl 0x00004010,%eax

    isRegistered +15 0000252d 891c24 movl %ebx,(%esp) +18 00002530 89442404 movl %eax,0x04(%esp)

    +22 00002534 e8252b0000 calll 0x0000505e-[(%esp,1) isRegistered] +27 00002539 84c0 testb %al,%al +29 0000253b 742b je 0x00002568

    From Apple's documentation available athttp://developer.apple.com/library/mac/#documentation/cocoa/reference/NSApplicationDelegate_Protocol/Reference/Reference.htmlyou get the following about applicationDidFinishLaunching:Delegates can implement this method to perform further initialization. This method is called afterthe application s main run loop has been started but before it has processed any events. If the

    application was launched by the user opening a file, the delegate s application:openFile: method iscalled before this method. If you want to perform initialization before any files are opened, implementthe applicationWillFinishLaunching: method in your delegate, which is called before application:openFile:.)

    This is a good place to start in Cocoa apps, because many developers start checking here if trials are ok,if serial numbers are ok, etc.This is more or less the behaviour we have experienced with the crackme, because we got that initialmessage telling us about what we need to do (we can speculate that the message w

    ill not appear if thecrackme is registered successfully).

    Getting back to that piece of code:-(void)[Level1 applicationDidFinishLaunching:] +0 0000251e 55 pushl %ebp +1 0000251f 89e5 movl %esp,%ebp +3 00002521 53 pushl %ebx +4 00002522 83ec24 subl $0x24,%esp +7 00002525 8b5d08 movl 0x08(%ebp),%ebx

  • 8/11/2019 Reversing MacOSX

    18/27

    +10 00002528 a110400000 movl 0x00004010,%eaxisRegistered

    +15 0000252d 891c24 movl %ebx,(%esp) +18 00002530 89442404 movl %eax,0x04(%esp) +22 00002534 e8252b0000 calll 0x0000505e

    -[(%esp,1) isRegistered]

  • 8/11/2019 Reversing MacOSX

    19/27

  • 8/11/2019 Reversing MacOSX

    20/27

    The alternative, is to modify the isRegistered method.The disassembly is:-(BOOL)[Level1 isRegistered] +0 00002a88 55 pushl %ebp +1 00002a89 89e5 movl %esp,%ebp +3 00002a8b 8b4508 movl 0x08(%ebp),%eax +6 00002a8e 0fb64020 movzbl 0x20(%eax),%eax +10 00002a92 c9 leave +11 00002a93 c3 ret

    You can modify this method to always return 1 (true).The most common way to do this is to replace the beginning of this method with the following code:xor eax, eaxinc eaxret

    Using the assemble command from gdb:gdb$ assembleInstructions will be written to stdout.Type instructions, one per line. Do not forget to use NASM assembler syntax!End with a line saying just "end".>xor eax,eax>inc eax

    >ret>end00000000 31C0 xor eax,eax00000002 40 inc eax00000003 C3 ret

    Those are the bytes you need to use and replace in the original method, 31 C0 40 c3.You need to patch 4 bytes, starting at 0x00002a88. The two first instructions total 3 bytes, so youwill "eat" space in the third instruction, which is 3 bytes long. Since you will patch a single bytein the third instruction, the rest of the code there will be most probably inval

    id. This isn't aproblem because we will not execute any code after the ret (return). To make this cleaner you couldNOP the two remaining bytes from the old third instruction.

    A variation of patching isRegistered, is to patch the code before the method iscalled.The original code is: +7 00002525 8b5d08 movl 0x08(%ebp),%ebx +10 00002528 a110400000 movl 0x00004010,%eax

    isRegistered +15 0000252d 891c24 movl %ebx,(%esp) +18 00002530 89442404 movl %eax,0x04(%esp)

    +22 00002534 e8252b0000 calll 0x0000505e-[(%esp,1) isRegistered]

  • 8/11/2019 Reversing MacOSX

    21/27

    and NOP the remaining bytes.So there are different ways to do this, based on available space, conditions and your lazyness ;-)

    As with the first alternative, you can try this in gdb before patching. Breakpoint the isRegistered methodat 0x00002a88 and run the crackme.

    $ gdb Challenge\ #1GNU gdb 6.3.50-20050815 (Apple version gdb-1344) (Mon Dec 28 15:21:35 UTC 2009)Copyright 2004 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries ........ done

    gdb$ b *0x00002a88Breakpoint 1 at 0x2a88gdb$ rReading symbols for shared libraries .+++++++.................................................................................. doneReading symbols for shared libraries . done

    Reading symbols for shared libraries . doneReading symbols for shared libraries . doneReading symbols for shared libraries . doneReading symbols for shared libraries . doneReading symbols for shared libraries . done

    Breakpoint 1, 0x00002a88 in -[Level1 isRegistered] ()--------------------------------------------------------------------------[regs] EAX: 0x00002A88 EBX: 0x00418820 ECX: 0x00000001 EDX: 0x00000000 o d I t sZ a P c

    ESI: 0xBFFFEA50 EDI: 0x00000002 EBP: 0xBFFFEA18 ESP: 0xBFFFE9EC EIP: 0x00002A88 CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F

    --------------------------------------------------------------------------[code]0x2a88: 55 push ebp0x2a89: 89 e5 mov ebp,esp0x2a8b: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]0x2a8e: 0f b6 40 20 movzx eax,BYTE PTR [eax+0x20]0x2a92: c9 leave0x2a93: c3 ret0x2a94: 55 push ebp0x2a95: b8 01 00 00 00 mov eax,0x1--------------------------------------------------------------------------------gdb$ set *0x2a88 = 0xc340c031gdb$ context--------------------------------------------------------------------------[regs]

    EAX: 0x00002A88 EBX: 0x00418820 ECX: 0x00000001 EDX: 0x00000000 o d I t sZ a P cESI: 0xBFFFEA50 EDI: 0x00000002 EBP: 0xBFFFEA18 ESP: 0xBFFFE9EC EIP: 0x000

    02A88 CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F--------------------------------------------------------------------------[code]0x2a88: 31 c0 xor eax,eax0x2a8a: 40 inc eax0x2a8b: c3 ret0x2a8c: 45 inc ebp

  • 8/11/2019 Reversing MacOSX

    22/27

    0x2a8d: 08 0f or BYTE PTR [edi],cl0x2a8f: b6 40 mov dh,0x400x2a91: 20 c9 and cl,cl0x2a93: c3 ret--------------------------------------------------------------------------------gdb$ c

    Voila, it's cracked.The set command will modify memory. As explained, we don't need to patch the remaining bytes, andsince our new bytes are 4 bytes (32bits) we don't need cast any values in the set command.For example, if you just wanted to patch a single byte you would use the following:set *(char *) address = 0x90

    3.1 - Patching the binary-------------------------

    To patch the binary, you will need to open it in an hex editor. Then you will need an offset. The offset is where the program is located.Mac OS X has what is called fat binaries (or universal binaries), meaning that a PPC and x86 version will be present in the same file.This obliges an extra step because you need to calculate the offset for the x86

    part (this tutorial is for x86!).I'm going to show you how to patch with the first alternative, the NOP.

    To verify if the binary is fat or universal, we can use otool command.$ otool -f Challenge\ #1Fat headersfat_magic 0xcafebabenfat_arch 2architecture 0 cputype 7 cpusubtype 3 capabilities 0x0 offset 4096

  • 8/11/2019 Reversing MacOSX

    23/27

    You should land at the correct offset. Check if the bytes match those we want to patch (742b). It should.Now you just need to replace 74 by 90 and 2B by 90 and save.Start Challenge #1 and voila, no more bad message! Our work is done...

    A word of caution while trying to calculate the offset. The previous paragraph about the formula to calculatecorrect offset is true if Intel x86 binary is the first one inside the fat binary. If PPC is first,then the formula is (offset - 0x1000 + offset_to_patch). You need to subtract 0x1000 because that's the headersize of PPC part. Not that hard to remember (I'm coding a small utility to do this math :) ).

    The easiest way to calculate the offset is to use the utility I created, offset.pl.You can download the latest version at http://reverse.put.as/wp-content/uploads/2011/02/offset1.3.pl_.gzor Ghalen's C version at http://reverse.put.as/wp-content/uploads/2009/06/ocalc.c

    To practice your patching skills, try to patch the isRegistered method :-)

    3.2 - Fishing a valid serial number

    -----------------------------------The routine that verifies if the serial is valid can be easily found in the disassembly listing.It's called -(BOOL)[Level1 validateSerial:forName:]. The name is very suggestive (another common mistake inOS X developers).

    You should study that routine to understand what's happening there. A basic scheme for a serial verificationroutine is:1) Verify if user serial number length is ok. If ok continue, else give an error.

    2) Compute the good serial number.3) Compare the user serial number with the good serial number.

    All these elements are present here. I will just dump my notes on what the codeis doing. Keep in mindthat valid serial number should be different in your case.

    Serial should be 8 chars in length, as this piece of code shows: +29 00002abb 83f808 cmpl $0x08,%eax

    A quick look at the whole method and we find the piece of code we are interested in: +369 00002c0f 891c24 movl %ebx,(%esp)

  • 8/11/2019 Reversing MacOSX

    24/27

    -[(%esp,1) isEqual:] +395 00002c29 84c0 testb %al,%al

  • 8/11/2019 Reversing MacOSX

    25/27

    { char name[256], *pname;

    printf("Macserialjunkies.com challenge #1 Keygen v0.1\n\n"); printf("Insert name:\n"); fflush(stdout); fgets(name, 256, stdin); if ((pname = strchr(name, '\n')) != NULL) { *pname = '\0'; }

    /* serial number is composed by 8 digits there are two algorithms, one for the first 4 digits and the other for the remaining*/

    // first block of four digits int i=0; int digit,multiplier=4;// mov eax,0x68db8bad int wtf = 0x68db8bad; int accumulator=0; int ecx=0;

    unsigned long long temp1; int temp2, temp3, temp4; int x=0; int stringsize = strlen(name); int firstblock,secondblock;

    for (x=0; x < stringsize ; x++){// movsx eax,BYTE PTR [edi+ebx] digit = name[i];// inc ebx i++;// imul eax,esi

    digit = digit * multiplier;// add esi,0x4 multiplier += 4;// shl edx,0x4// sub edx,eax digit = (digit > 32;// mov eax,ecx

    // sar eax,0x1f temp2 = ecx >> 0x1f;// sar edx,0xc temp1 = temp1 >> 0xc;// sub edx,eax temp3 = temp1 - temp2;// imul edx,edx,0x2710 temp4 = temp1 * 0x2710;// sub eax,edx ecx = ecx - temp4;

  • 8/11/2019 Reversing MacOSX

    26/27

    }// the last ecx is the good first serial partfirstblock = ecx;

    // second block i=0; multiplier = 4; int edx; x=0; ecx=0; int firstsar, secondsar;

    for (x=0; x < stringsize ; x++){//movsx eax,BYTE PTR [edi+ebx] digit = name[i];// inc ebx i++;// imul eax,esi digit = digit * multiplier;// add esi,0x8 multiplier += 8;// lea edx,[eax+eax*4]

    edx = digit + digit * 4;// lea edx,[eax+edx*2+0x2d] edx = digit + edx*2 + 0x2d;

    ecx = ecx + edx;

    temp1 = (unsigned long long) ecx * wtf; edx = temp1 >> 32;

    firstsar = ecx >> 0x1f; secondsar = edx >> 0xc;

    temp2 = secondsar - firstsar;

    edx = secondsar * 0x2710;

    temp3 = ecx - edx;}// 2nd part of good serial secondblock = temp3;

    // convert to decimal and printprintf("Serial number is: %04d%04d\n", firstblock, secondblock);printf("Byeeeeeee!\n");}----- CUT HERE ---------

    4 - Conclusion--------------

    And here we are, at the end of this long tutorial. I hope you have enjoyed it and learnt something with it.Now you should have a basic framework and ability to work with the basic tools.To advance further, you needto find more targets and practice with them. Breaking protections is a good wayto learn reverse

  • 8/11/2019 Reversing MacOSX

    27/27

    engineering, because you always have a goal, breaking the protection. You will need to think andresearch so you can advance, that is the really fun part about reversing.Sometimes you will not be able to advance a target, maybe you should postpone it and get back at itlater when your skills improved. This was my contribution to introduce you to this world, the next step depends on you.

    If you have any suggestions, doubts or found any error, please feel free to leave a comment at myblog http://reverse.put.as or drop an email at reverse AT put.as

    Have fun!fG!