Sponsored Links

Sponsored Links

Results 1 to 5 of 5



  1. #1
    Forum Moderator PS3 News's Avatar
    Join Date
    Apr 2005
    Posts
    27,455
    Sponsored Links

    Guide to Reversing on PS3 Linux Using the GNU Toolchain

    Sponsored Links
    Today Disane has made available a guide to reversing on PS3 Linux using the GNU Toolchain.

    Prerequisites for it include computer science, assembly and C knowledge along with having available the GNU toolchain for the Cell Processor installed on PS3 Linux.

    PPC32-64 assembly:

    [Register or Login to view links]
    [Register or Login to view links]
    [Register or Login to view links]
    [Register or Login to view links]
    [Register or Login to view links]
    [Register or Login to view links]
    [Register or Login to view links]
    [Register or Login to view links]

    Official PPC32-64 Docs:

    [Register or Login to view links]
    [Register or Login to view links]

    Cell Processor SPU assembly:

    [Register or Login to view links]
    [Register or Login to view links]
    [Register or Login to view links]
    [Register or Login to view links]

    We are also going to use the following documentations when we are reversing SPU code:

    [Register or Login to view links]
    [Register or Login to view links]

    So now that we are through the introduction. Let's get down and dirty. The first thing we need is an application we can reverse. Well, we could try and reverse existing applications compiled on our PPC64 Linux but that would take too much time and besides this is not a book. So we are going to start with something very basic.

    The application we are going to reverse today is the all times classic "Guessing Game" written in C. The idea is simple. The computer generates a number between 1 and 10 and the player has to guess which number has the computer generated. Simple, right? In C probably yes but in PPC and SPU assembly this could be a real challenge even for experienced programmers.

    Well we are not going to write the game in PPC and SPU assembly simply because of two reasons. The first one is that C is portable code. We can compile our C code to run on the PPU or on the SPU. Cool, what's the other reason? Well the other reason is that this is a tutorial on reversing SPU and PPU code and not an assembly tutorial.

    About the sample code I'm going to show you. We are not going to use classes or anything fancy this is a classic C (sequential programming 101) so no Object Oriented Programming introduced. No exceptions to invoke or anything fancy. We are going to use one single Game Loop to keep the game going until the player wins (yeah you can't lose in this game, but you can modify it if you want, the possibilities are endless).

    Alright so let's fire up Linux on our PS3 and open up the Terminal. I don't know about you, but I've got Ubuntu 10.4 on my machine. Locate a nice spot like ~/Projects/Reversing/guessing_game/ (use cd command to get to you home directory then mkdir to create the directories you need) and here we can create a text document using gedit or nano (type in gedit or nano).

    The rest of the Guide to Reversing on PS3 Linux Using the GNU Toolchain can be found HERE or linked above!


    Our C code is the following:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    void initialize();
    void player_guess();
    
    /* the players guess */
    int guess;
    
    /* the number the player needs to guess*/
    int game_number;
    
    int main(int argc, char* argv)
    {
       initialize();
       
       /* the game wont stop until the player finds the number */
       do
       {
          player_guess();
       }
       while(guess != game_number);
       
       /* congratulate the player */
       printf("Oh goody, you guessed the number!\n");
       printf("the number was indeed %d. \nCongratulations !!!\n", game_number);
       /* end... */
       return 0;
    }
    
    void initialize()
    {
       printf("Welcome to the Guessing game!\n");
       
       /* initialize random seed: */
              srand ( time(NULL) );
       
       /* generate a game number */
       game_number = rand() % 10 + 1;
       
       printf("A random number was generated between 1 to 10 for you.\n");
    }
    
    void player_guess()
    {
          printf("Please place your bet: ");
          scanf("%d", &guess);
          
          /* the player missed the number, let's help her/him out a little bit */
          if(guess > game_number)
          {
             printf("Nah, sorry you missed it! The number your looking for is actually SMALLER than %d.\n", guess);
          }
          else if(guess < game_number)
          {
             printf("Nah, sorry you missed it! The number your looking for is actually LARGER than %d.\n", guess);
          }
    }
    Save the text as a C source code file. Let’s name it ppe_guessing_game.c .I think the sample code is well commented so I won’t be explaining what it does. I just assume you know C. (I think even beginner programmers should be able to understand the code.) Let’s compile this baby using gcc. The command looks as the following:
    Code:
    gcc ppe_guessing_game.c –o PPC32_guessing
    That’s our PPU code. Nicely done so far! Now we are going to create another source code and name it spe_guessing_game.c. Our SPU code is a little bit different than the PPU code. Take a look at it first to see if you can spot the differences and then I will tell you why this code is different:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    void initialize();
    void player_guess();
    
    /* variable to the number of the running SPE */
    unsigned long long host;
    
    /* the players guess */
    int guess;
    
    /* the number the player needs to guess*/
    int game_number;
    
    int main(unsigned long long spe, unsigned long long argp, unsigned long long envp)
    
    {
       host = spe;
       initialize();
       
       /* the game wont stop until the player finds the number */
       do
       {
          player_guess();
       }
       while(guess != game_number);
       
       /* congratulate the player */
       printf("Oh goody, you guessed the number!\n");
       printf("the number was indeed %d. \nCongratulations !!!\n", game_number);
       /* end... */
       return 0;
    }
    
    void initialize()
    {
       printf("Welcome to the Guessing game!\n");
       printf("Our host for today is SPE number %d!\n", host);
    
       /* initialize random seed: */
              srand ( time(NULL) );
       
       /* generate a game number */
       game_number = rand() % 10 + 1;
       
       printf("A random number was generated between 1 to 10 for you.\n");
    }
    
    void player_guess()
    {
          printf("Please place your bet: ");
          scanf("%d", &guess);
          
          /* the player missed the number, let's help her/him out a little bit */
          if(guess > game_number)
          {
             printf("Nah, sorry you missed it! The number your looking for is actually SMALLER than %d.\n", guess);
          }
          else if(guess < game_number)
          {
             printf("Nah, sorry you missed it! The number your looking for is actually LARGER than %d.\n", guess);
          }
    }
    As you can see the main() has changed a little bit, we have some interesting arguments here. Let’s see what they are:

    unsigned long long spe: is the SPU’s ID which is a unique SPU task identifier assigned by the operating system. Which means the OS selects the SPE where the program get’s loaded into.
    unsigned long long argp: is an effective address (EA) in the main storage to application parameters.
    unsigned long long env: The environment pointer, which is an effective address (EA) in main storage to runtime environment information. I really don’t want to get into how the SPU code is getting loaded and all the other mysterious questions you might raise here. So please refer to this tutorial if you have questions about programming the SPU:
    [Register or Login to view links]

    Okay so the SPE version of the guessing game has some little extra. It stores the SPE number in a variable and displays the ID of the SPE when the game starts up. Other than that these two games are all the same. Compile the game with the following command in your Terminal:
    Code:
    spu-gcc spe_guessing_game.c –o SPU_guessing
    We are done. Let’s check if the games are working fine. Type in:
    Code:
    ./PPU_guessing
    Test the game to see how it works then type in:
    Code:
    ./SPU_guessing
    Again, test the game then close it. If everything has gone well then we have our Binaries. Good work so far.
    Code:
    readelf and objdump
    This section will talk about using readelf, objdump, spu-readelf and spu-objdump . If you haven’t used these tools before then you might want to take a look at the following tutorial on exploring ELF files with readelf and objdump: [Register or Login to view links]

    I will only going to show you what kind of arguments we are going to use and tell a little bit about these tools.

    readelf:
    So let’s start with the readelf. In this tutorial we are going to use the readelf file to view ELF headers and to detect sections of the executable ELF binary we created when we compiled the simple game above this section. So for starters the readelf arguments in general look like this:
    Code:
    readelf –h <File_Name> - allows the user to view the header of the ELF binary.
    readelf –S <File_Name> - read section headers
    Navigate to the PPU_guessing binary using the Terminal and let’s type in readelf –h PPU_guessing to view the header of the PPU_guessing game:



    Alright, so now we know that we are dealing with PPU code. We know that Data is Big Endian code and it’s an EXEC (Executable File) file. We know that there are 38 Sections (This could probably hold debug information as well). We also see where the entry point to the program is: 0x10000430.
    Now let’s run readelf –S PPU_guessing. We get the following:



    As you can see this has lots info we can use. Like what sections are executable/readable/writable codes (by looking at the Flags column). Also we have the sizes of each section. The ones that are zeroed out are probably not interesting anyways. We also have debug sections you can check out. There’s a major difference between debug ELF executables and non-debug ELF executables. There are less sections in the ELF file and also the executable code itself is shorter, since you don’t have to store every register on the stack to make the value available to read by the debugger (ppu/spu-gdb). The list your seeing now won’t be explained now. We will discuss it in the objdump section of this tutorial. We are actually going to use objdump to view what’s inside of these sections.

    Now, try and use spu-readelf –h and spu-readelf –S on your SPU_guessing:





    As you can see the spu-elf consists of fewer sections. This means fewer data and code to worry about. Ok, so we have a bunch of sections here but how do we check what’s inside in each section. That’s where the objdump comes into play.

    objdump: objdump is the main tool we are going to use for reversing. You can look at it as a dump IDA disassembler but don’t be fooled. objdump can be still very powerful. First of all it allows us to view PPU and SPU code. Which IDA currently does not implement is the SPU disassemble and without the proper SPU processor plugin you can’t view/reverse SPU code using IDA. We are going to use objdump for two main things. The first one is viewing data and addresses. The second thing is viewing PPU and SPU code plus the address of each code segment.

    If you look at the top readelf/spu-readelf –S listings. You should see that there are many sections to disassemble and view. Let’s take a look at the most important sections which we are going to touch in this tutorial.
    PPU:

    .init: Holds the process initialization code. Gets called before main().
    .text: Executable section. This is where the program code goes. You might think that only main() and the other functions which are used by the application reside in this section. Well, the truth is that you get a lot more than that. More details in the “Reversing PowerPC 32 code” section of this tutorial.
    .fini: Holds the process termination code. Gets executed when your program exits normally.
    .rodata: A non writable section. Holds read only data which are strings, mostly. An ASCII code table could come in handy when dealing with .rodata.
    .bss: Uninitialized or so called “null” data goes here. When the program executes this data gets initialized as 0.
    .data: Initialized data.
    .got: The Global Offset Table. Nearly everything gets redirected to this address. It’s very handy to know this address.
    .plt: The Procedure Linkage Table. The base address for some libc function calls.

    SPU:
    note.spu_name: holds the name of the executable. For example: SPU_NAME.SPU_guessing
    For more information on the ELF and it’s special sections check out: [Register or Login to view links]

    Now, let’s check out some of the sections with objdump. Here’s some of the arguments you can give to objdump:
    Code:
    objdump –d <File_Name> ,disassembles the file completely
    objdump –D <File_Name>, does the same as the previous flag
    objdump –s <File_Name>,diplay content (hex and string)
    objdump –S <File_Name>,mix disassembly with content
    So let’s go ahead and display the .rodata section of the PPU_guessing using the command below:
    Code:
    objdump –s –j .rodata PPU_guessing


    Here we can view the read-only data (like strings) which are located in our program. The first column shows the address while the other 4 next to this shows the data in hex (each row holds 16 bytes of data, remember that one character is 1 byte which can be represented with 2 hexadecimal digits).

    Let’s check out what the following command gives us:
    Code:
    spu-objdump –s –j .rodata SPU_guessing


    Now, you might think hex-editing is the same as hacking. Not at all dear Sir, you are wrong. Hacking is about reversing parts of the application which you are interested in or want to abuse (remove nag screens, remove trial counter, make the application fully functional if it’s a shareware). In order to do that, you’ll need to reverse engineer parts of the application and this is the part where assembly knowledge comes in handy. In the next section we are going to dive deep into reversing our PPU_guessing program.

    Reversing PowerPC 32 code

    Before we go into detail, there’s something I want to show you. If you look at the .text section using the command below:
    Code:
    objdump –D –j .text PPU_guessing
    As I mentioned above the .text section has more on store for us than you would expect. Normally you are expecting to get main(), initialize(), player_guess() but you get things like:

    _start: The first thing that gets executed by the Operating System. Also sets up the stack and It’s in fact a wrapper for __libc_start_main. Which is a library function inside libc. It’s interesting to note that we can actually create our own _start function enabling us to make the start code smaller.
    _do_global_dtors_aux: The destructor function for this program.
    call_do_global_dtors_aux
    frame_dummy
    call_fame_dummy
    libc_csu_fini
    libc_csu_init
    _do_globabl_ctors_aux: The constructor function for this program.
    call_do_global_ctors_aux
    srand@plt: srand()
    _gmon_start__@plt
    __libc_start_main@plt: initializes the C library and calls main()
    printf@plt: calls printf()
    time@plt: calls time()
    __isoc99_scanf@plt: calls scanf()
    puts@plt: calls puts() although we know from the source code this wasn’t called specifically you’ll see how the compiler has swapped some of the printf()s to puts().
    rand@plt: calls rand()
    _glink
    _glink_plt_resolver: resolves linking when the program executes.

    It’s nice to know some of these (C runtime) functions as well, cause at least we know that they’re not interesting for us to reverse. The good thing is that we know which functions are being called from libc this can make our job a lot easier.

    Check this out for more info on the above functions: [Register or Login to view links]

    So now that we know what not to reverse there are only 3 functions left. Let’s view them:
    Code:
    1000059c <main>:
    1000059c:   94 21 ff e0    stwu    r1,-32(r1)
    100005a0:   7c 08 02 a6    mflr    r0
    100005a4:   90 01 00 24    stw     r0,36(r1)
    100005a8:   93 e1 00 1c    stw     r31,28(r1)
    100005ac:   7c 3f 0b 78    mr      r31,r1 
    100005b0:   90 7f 00 0c    stw     r3,12(r31)
    100005b4:   90 9f 00 08    stw     r4,8(r31)
    100005b8:   48 00 00 79    bl      10000630 <initialize>
    100005bc:   48 00 01 0d    bl      100006c8 <player_guess>
    100005c0:   3c 00 10 01    lis     r0,4097
    100005c4:   7c 0b 03 78    mr      r11,r0
    100005c8:   81 2b 10 30    lwz     r9,4144(r11)
    100005cc:   3c 00 10 01    lis     r0,4097
    100005d0:   7c 0b 03 78    mr      r11,r0
    100005d4:   80 0b 10 2c    lwz     r0,4140(r11)
    100005d8:   7f 89 00 00    cmpw    cr7,r9,r0
    100005dc:   40 9e ff e0    bne+    cr7,100005bc <main+0x20>
    100005e0:   3c 00 10 00    lis     r0,4096
    100005e4:   30 60 0a 2c    addic   r3,r0,2604
    100005e8:   48 00 03 79    bl      10000960 <puts@plt>
    100005ec:   3c 00 10 00    lis     r0,4096
    100005f0:   31 20 0a 50    addic   r9,r0,2640
    100005f4:   3c 00 10 01    lis     r0,4097
    100005f8:   7c 0b 03 78    mr      r11,r0
    100005fc:   80 0b 10 2c    lwz     r0,4140(r11)
    10000600:   7d 23 4b 78    mr      r3,r9
    10000604:   7c 04 03 78    mr      r4,r0
    10000608:   4c c6 31 82    crclr   4*cr1+eq
    1000060c:   48 00 03 25    bl      10000930 <printf@plt>
    10000610:   38 00 00 00    li      r0,0
    10000614:   7c 03 03 78    mr      r3,r0
    10000618:   39 7f 00 20    addi    r11,r31,32
    1000061c:   80 0b 00 04    lwz     r0,4(r11)
    10000620:   7c 08 03 a6    mtlr    r0
    10000624:   83 eb ff fc    lwz     r31,-4(r11)
    10000628:   7d 61 5b 78    mr      r1,r11
    1000062c:   4e 80 00 20    blr
    
    10000630 <initialize>:
    10000630:   94 21 ff e0    stwu    r1,-32(r1)
    10000634:   7c 08 02 a6    mflr    r0
    10000638:   90 01 00 24    stw     r0,36(r1)
    1000063c:   93 e1 00 1c    stw     r31,28(r1)
    10000640:   7c 3f 0b 78    mr      r31,r1
    10000644:   3c 00 10 00    lis     r0,4096
    10000648:   30 60 0a 80    addic   r3,r0,2688
    1000064c:   48 00 03 15    bl      10000960 <puts@plt>
    10000650:   38 60 00 00    li      r3,0
    10000654:   48 00 02 ed    bl      10000940 <time@plt>
    10000658:   7c 60 1b 78    mr      r0,r3
    1000065c:   7c 03 03 78    mr      r3,r0
    10000660:   48 00 02 a1    bl      10000900 <srand@plt>
    10000664:   48 00 03 0d    bl      10000970 <rand@plt>
    10000668:   7c 69 1b 78    mr      r9,r3
    1000066c:   3c 00 66 66    lis     r0,26214
    10000670:   60 00 66 67    ori     r0,r0,26215
    10000674:   7c 09 00 96    mulhw   r0,r9,r0
    10000678:   7c 0b 16 70    srawi   r11,r0,2
    1000067c:   7d 20 fe 70    srawi   r0,r9,31
    10000680:   7c 00 58 50    subf    r0,r0,r11
    10000684:   54 00 08 3c    rlwinm  r0,r0,1,0,30
    10000688:   54 0b 10 3a    rlwinm  r11,r0,2,0,29
    1000068c:   7c 00 5a 14    add     r0,r0,r11
    10000690:   7c 00 48 50    subf    r0,r0,r9
    10000694:   31 20 00 01    addic   r9,r0,1
    10000698:   3c 00 10 01    lis     r0,4097
    1000069c:   7c 0b 03 78    mr      r11,r0
    100006a0:   91 2b 10 2c    stw     r9,4140(r11)
    100006a4:   3c 00 10 00    lis     r0,4096
    100006a8:   30 60 0a a0    addic   r3,r0,2720
    100006ac:   48 00 02 b5    bl      10000960 <puts@plt>
    100006b0:   39 7f 00 20    addi    r11,r31,32
    100006b4:   80 0b 00 04    lwz     r0,4(r11)
    100006b8:   7c 08 03 a6    mtlr    r0
    100006bc:   83 eb ff fc    lwz     r31,-4(r11)
    100006c0:   7d 61 5b 78    mr      r1,r11
    100006c4:   4e 80 00 20    blr
    
    100006c8 <player_guess>:
    100006c8:   94 21 ff e0    stwu    r1,-32(r1)
    100006cc:   7c 08 02 a6    mflr    r0
    100006d0:   90 01 00 24    stw     r0,36(r1)
    100006d4:   93 e1 00 1c    stw     r31,28(r1)
    100006d8:   7c 3f 0b 78    mr      r31,r1
    100006dc:   3c 00 10 00    lis     r0,4096
    100006e0:   30 00 0a d8    addic   r0,r0,2776
    100006e4:   7c 03 03 78    mr      r3,r0
    100006e8:   4c c6 31 82    crclr   4*cr1+eq
    100006ec:   48 00 02 45    bl      10000930 <printf@plt>
    100006f0:   3c 00 10 00    lis     r0,4096
    100006f4:   30 00 0a f0    addic   r0,r0,2800
    100006f8:   7c 03 03 78    mr      r3,r0
    100006fc:   3c 00 10 01    lis     r0,4097
    10000700:   30 80 10 30    addic   r4,r0,4144
    10000704:   4c c6 31 82    crclr   4*cr1+eq
    10000708:   48 00 02 49    bl      10000950 <__isoc99_scanf@plt>
    1000070c:   3c 00 10 01    lis     r0,4097
    10000710:   7c 0b 03 78    mr      r11,r0
    10000714:   81 2b 10 30    lwz     r9,4144(r11)
    10000718:   3c 00 10 01    lis     r0,4097
    1000071c:   7c 0b 03 78    mr      r11,r0
    10000720:   80 0b 10 2c    lwz     r0,4140(r11)
    10000724:   7f 89 00 00    cmpw    cr7,r9,r0
    10000728:   40 9d 00 2c    ble-    cr7,10000754 <player_guess+0x8c>
    1000072c:   3c 00 10 00    lis     r0,4096
    10000730:   31 20 0a f4    addic   r9,r0,2804
    10000734:   3c 00 10 01    lis     r0,4097
    10000738:   7c 0b 03 78    mr      r11,r0
    1000073c:   80 0b 10 30    lwz     r0,4144(r11)
    10000740:   7d 23 4b 78    mr      r3,r9
    10000744:   7c 04 03 78    mr      r4,r0
    10000748:   4c c6 31 82    crclr   4*cr1+eq
    1000074c:   48 00 01 e5    bl      10000930 <printf@plt>
    10000750:   48 00 00 48    b       10000798 <player_guess+0xd0>
    10000754:   3c 00 10 01    lis     r0,4097
    10000758:   7c 0b 03 78    mr      r11,r0
    1000075c:   81 2b 10 30    lwz     r9,4144(r11)
    10000760:   3c 00 10 01    lis     r0,4097
    10000764:   7c 0b 03 78    mr      r11,r0
    10000768:   80 0b 10 2c    lwz     r0,4140(r11)
    1000076c:   7f 89 00 00    cmpw    cr7,r9,r0
    10000770:   40 9c 00 28    bge-    cr7,10000798 <player_guess+0xd0>
    10000774:   3c 00 10 00    lis     r0,4096
    10000778:   31 20 0b 48    addic   r9,r0,2888
    1000077c:   3c 00 10 01    lis     r0,4097
    10000780:   7c 0b 03 78    mr      r11,r0
    10000784:   80 0b 10 30    lwz     r0,4144(r11)
    10000788:   7d 23 4b 78    mr      r3,r9
    1000078c:   7c 04 03 78    mr      r4,r0
    10000790:   4c c6 31 82    crclr   4*cr1+eq
    10000794:   48 00 01 9d    bl      10000930 <printf@plt>
    10000798:   39 7f 00 20    addi    r11,r31,32
    1000079c:   80 0b 00 04    lwz     r0,4(r11)
    100007a0:   7c 08 03 a6    mtlr    r0
    100007a4:   83 eb ff fc    lwz     r31,-4(r11)
    100007a8:   7d 61 5b 78    mr      r1,r11
    100007ac:   4e 80 00 20    blr
    Still a lot of code to look at but it’s doable First of all, we need to review our knowledge on the PPC ABI and a little bit of our assembly knowledge to make a sense out of this huge blob of code. Let’s start with the ABI.

    PPC ABI review: First of all we won’t be reviewing the whole ABI for that you might want to read the articles in the Prologue section of this tutorial.

    r0 Volatile register used in function prologues (used to hold the LR)
    r1 Stack frame pointer (SP)
    r2 TOC pointer
    r3 Volatile parameter and return value register (sometimes used as parameter 1)
    r4-r10 Volatile registers used for function parameters 2 to 7
    r11 Volatile register used in calls by pointer and as an
    environment pointer for languages which require one
    r12 Volatile register used for exception handling and glink code
    r13 Reserved for use as system thread ID
    r14-r31 Nonvolatile registers used for local variables

    f0 Volatile scratch register
    f1-f4 Volatile floating point parameter and return value registers
    f5-f13 Volatile floating point parameter registers
    f14-f31 Nonvolatile registers

    LR Link register (volatile) you can’t use it as a general purpose register
    use mflr (move from LR) and mtlr (move to LR) to access its contents
    CTR Loop counter register (volatile)
    XER Fixed point exception register (volatile)
    FPSCR Floating point status and control register (volatile)

    Condition Registers:
    CR0-CR1 Volatile condition code register fields
    CR2-CR4 Nonvolatile condition code register fields
    CR5-CR7 Volatile condition code register fields

    The PPU stack frame organization:



    The information above comes from the [Register or Login to view links] document.

    Here’s a little bit of an explanation on what the Link Register is and what the Stack Pointer is:

    Link Register(LR):
    The LR is actually a special purpose register which holds the address to return to when a function call completes. In other words this register stores an address where the program counter will jump to when the execution of the function is complete. It’s always moved from the LR and stored on r0 when a new stack is being built.

    Stack Pointer (stored on r1):
    Stores an address, that points to the top of the current stack. It’s also important to note that not every stack has the same size. The size of the Stack depends on the local variables and the number of saved registers on the stack. But there is a minimum size which the Stack must have where it can store the LR and the SP. When your decrementing the stack you are “allocating” Stack space and when your incrementing it then you are actually “deleting” the Stack.

    After this small review of the ABI let’s get back to our main() function and it’s PPU code:

    Setting up the Stack: Prologue and Epilogue
    In this section we are going to review how the stack is handled and how the ABI works. This will make our job easier to see what data is being stored on the stack. We are interested in Local Variables and looking at how the Stack is being setup, we can detect them.

    Prologue Phase:
    In the first few lines of our main function, we can see how the Stack is being setup. This is an important part which we need to investigate.
    Code:
    stwu    r1,-32(r1)
    Here we increment the Stack Pointer by -32, which means we move the pointer downwards by 32 Bytes and we store the stack pointer back in r1. This is why we call this instruction Store Word and Update. We also store the Stack Pointer (also known as the Back Chain Pointer, which is a Pointer to the previous Stack) on this address. This is how you allocate space on the stack. We always go from the higher address to the lower and we use a pointer to tell which Stack are we at. So now we store the “base” address of our new stack on r1 and now we can refer to r1 as the Stack Pointer. Remember that we said that the Back Chain is at SP+0 which is true. We are at that spot.
    Code:
    mflr    r0
    Here we Move the LR into r0. So we can save it:
    Code:
    stw     r0,36(r1)
    on SP+36 which is an interesting thing. Remember that we already decremented the SP to create our Stack. But now we are actually jumping back to our previous stack and place the LR on the “bottom” of the previous Stack.
    Code:
    mr      r31,r1
    Here we move the contents of r1 into r31 to create a frame pointer (a pointer to the top of the current stack).
    Code:
    stw     r3,12(r31)
    stw     r4,8(r31)
    These two instructions store argc and argv on the stack. Note that we are using the frame pointer as the base address.

    Program Code:
    Code:
    bl      10000630 <initialize>
    bl      100006c8 <player_guess>
    Here we can see 2 Branch and Link instructions. Which means the instruction pointer (or program counter) jumps on to initialize() and saves the address of where it jumped from on to the LR and increments it by 4(Bytes) so when the blr (branch to the address in LR) is called from initialize() the program counter won’t jump back to the bl initialize() code rather on to the next instruction(bl player_guess). We won’t be following the program counter for now cause we haven’t really figured out what else does the main() function perform. So let’s move further:

    So far we know that main() calls initialize() and player_guess() right after initialize() was called.
    Code:
    lis     r0,4097
    mr      r11,r0
    lwz     r9,4144(r11)
    
    lis     r0,4097
    mr      r11,r0
    lwz     r0,4140(r11)
    
    cmpw    cr7,r9,r0
    bne+    cr7,100005bc <main+0x20>
    So what happens here? That’s the million dollar question. Actually this isn’t that hard to find out. As you can see the first instruction loads in 4097 into r0, but this time it shifts the value by 2 bytes. Let’s see how this looks like:

    4097 (decimal) is equal to 0x1001 (hexa-decimal, just grab a calculator ). After loaded into r0 it looks like this:
    0x10010000 in the next instruction we move this value into r11 from r0 and use this as a base to add 4144. Let’s see how we add the two addressed to create one:
    Code:
      0x10010000
    + 0x00001030
    ------------
      0x10011030
    We get this value in r9. What is this? Definitely not a value cause it’s too large to be some kind of value of a variable. But if you look at the address where this instruction is (100005c0) you should notice that the value we got also starts with 0x100… Hmmm are you thinking what I’m thinking? Yeah this is an address in our program. But the value is so large that it’s beyond the .text section. So where does this address point to? Let’s type in readelf –S PPU_guessing again to view the sizes and addresses of each section.

    Just as I expected: our address is inside the .sbss. The .sbss is exactly 8 Bytes long. So there’s probably data inside. Let’s open up the .sbss using objdump -D -j .sbss PPU_guessing.

    At the address 10011030 we have <guess> .Bingo! We can see that r9 stores the value of guess. I think we can move on to the next instruction. Again, we have these three instructions:
    Code:
    100005cc: 3c 00 10 01 lis r0,4097
    100005d0: 7c 0b 03 78 mr r11,r0
    100005d4: 80 0b 10 2c lwz r0,4140(r11)
    I highlighted the most important part in these 3 instructions. Yes, you can view the address if you combine these two. So we get 0x1001102c inside r0. Which is an address in the .sbss to <game_number>. This means r0 stores the value of game_number. Great job so far. Now, we know that we are loading in 2 important values into r9 and r0. But here comes something even more important. These two values are being compared by the following instruction:
    Code:
    cmpw    cr7,r9,r0
    Basically what happens here is that. We compare these two “words”. If you look back at the previous instructions then you can see that these two values were loaded in as “words”, a word is exactly 4 Bytes long, remember that on 32 bit mode an address is 4 Bytes long, quite explains why you can only address 4 GBs of memory right? . But that’s not important what’s important is that we are comparing these two words, r9 with r0 and we are setting the bits on cr7 (Condition Register 7). After the bits are set we move on to our next instruction:
    Code:
    bne+    cr7,100005bc <main+0x20>
    Ok, so we are branching again. Our instruction is the Branch if not Equal (+ predict, that the branch is likely to be taken). Very interesting fact is that the machine knows that in most cases the player will be wrong . If the branch hint was wrong and the player guessed the number then the processor has to unload the code it has loaded (the hinted code) and loads in the code which it did not predict. Branch prediction is good for optimization but I think you don’t want to use it random situations (especially in real time applications). In this case we can assume that the player will be false and besides we need to take the other branch only once so we won’t lose too much overall speed. So let’s get back to our instruction. We are checking the bits inside cr7 and if the prediction was right then we go back to this instruction:
    Code:
    100005bc:   48 00 01 0d    bl      100006c8 <player_guess>
    Oh, yes! This means that if the two values are not equal then the Program Counter jumps back to player_guess. Which we can assume is the function which takes the guess value from the player. But we will see once we get there. We now know that main() has some very important role in this program. It loads in the values guess and game_number and compares them and branches according to the result. Let’s see what happens if the player was correct:
    Code:
    100005e0: 3c 00 10 00 lis r0,4096
    100005e4: 30 60 0a 2c addic r3,r0,2604
    100005e8: 48 00 03 79 bl 10000960 <puts@plt>
    Again we can see Load Immediate Shifted and his buddy Add Immediate with Carry. But this time the situation is a bit different. The 0x10000a2c address gets loaded into r3, which makes me want to think that we are witnessing a function call. According to the ABI the r3 is the first argument that gets loaded when a function is being called. If you look at the third instruction, you can see that indeed we are branching and Linking into puts(). puts(), “WTF?” you might ask. Why is puts() being called and not printf(). I guess the answer is simple but you won’t like it. The compiler has decided to use puts() instead of printf() cause of one reason and that has something to do with the address we are loading into r3. Let’s check the address:
    Code:
    readelf –S PPU_guessing
    Our address this time is inside .rodata according to the section addresses. If your still scratching your head how did I come to this conclusion then let’s check the section addresses together:
    Code:
    .fini           100009e0
    .rodata         10000a18
    .eh_frame_hdr   10000b9c
    Ok, we have 0x10000a2c which is greater than 100009e0 (.fini ) and 10000a18 (.rodata) but not greater than 10000b9c(.eh_frame_hdr). Which makes me want to think that the address we are looking for is between .rodata and .eh_frame_hrd. So we open up .rodata (this is where read-only data is stored, makes sense, right?):
    Code:
    10000a28 00020001 4f682067 6f6f6479 2c20796f   ....Oh goody, yo
    10000a38 75206775 65737365 64207468 65206e75  u guessed the nu
    10000a48 6d626572 21000000 74686520 6e756d62  mber!...the numb
    Well, there’s no such address mentioned here. But we can guess that the address is somewhere here. So let’s look at 0x10000a28. We need to calculate where the data resides. Let’s subtract 0x10000a2c with 0x10000a28:
    Code:
       0x10000a2c
      -0x10000a28
    --------------
       0x00000004
    That means 4 Bytes. So our data starts from here:
    Code:
    00020001 4f682067 6f6f6479 2c20796f
    Here we need to cut 4 bytes which means our data is the one in the green highlight and the red is the one we cut off (remember 1 Byte is two “digits” in Hex-Decimal). We can check if we are looking at the data we are searching for. We need an ASCII table to see that. Since we know that each character is two Hex digit. We can decode the characters from the hex-decimal code manually:
    Code:
    4f 68 20 67 6f 6f 64 79 2c 20 79 6f
    -----------------------------------
    O  h     g  o  o  d  y  ,     y  o
    I think this is it we’ve found the data. Let’s see how it looks like:
    Code:
    10000a28 00020001 4f682067 6f6f6479 2c20796f ....Oh goody, yo
    10000a38 75206775 65737365 64207468 65206e75 u guessed the nu
    10000a48 6d626572 21000000 74686520 6e756d62 mber!...the numb
    Our data is the one I highlighted with green. Okay nice so puts() writes out “Oh goody, you guessed the number!”.
    Since there’s no data to display GCC thought that puts() is enough to do the job there’s no need for printf(). So how did I find out where’s the end of the string in .rodata? It’s simple if you’ve ever ran the program your reversing then it’s pretty easy to tell how strings are displayed. You can see them and write down the messages the program writes out. There’s another way to check this as you can see there’s a little bit of gap between each string. The gab consists of 0’s. Let’s move on to our next instruction series. This next one is also a function call. But this time we are calling printf(). This means we are going to display data as well as strings. Let’s see how this is preformed:
    Code:
    100005ec:   3c 00 10 00    lis     r0,4096
    100005f0:   31 20 0a 50    addic   r9,r0,2640
    100005f4:   3c 00 10 01    lis     r0,4097
    100005f8:   7c 0b 03 78    mr      r11,r0
    100005fc:   80 0b 10 2c    lwz     r0,4140(r11)
    10000600:   7d 23 4b 78    mr      r3,r9
    10000604:   7c 04 03 78    mr      r4,r0
    10000608:   4c c6 31 82    crclr   4*cr1+eq
    1000060c:   48 00 03 25    bl      10000930 <printf@plt>
    Alright let’s check the addresses. 0x10000a50 points to “the number was indeed %d./nCongratulations!!!” where we can see data as well and this data is stored on 0x1001102c very familiar address. Isn’t this game_number? Indeed it is game_number. After loading the string and data into r9 and r0 we move the string from r9 into r3 and the data from r0 into r4. Then something interesting happens:
    Code:
    crclr 4*cr1+eq
    crclr stands for Condition Register Clear. Basically what it does is simple. It xors the Condition Register with its own values which means it clears every bit to zero. But here we are only touching cr1 more specifically we are clearing the equal bits. Which is the bit field of cr1 that indicates if the result was equal or not. I have no idea why is GCC doing this :-/

    Anyway, after that we Branch and Link into printf() with the two arguments to print out the string and the data together.
    Epilogue Phase:
    From now on we are moving into the Epilogue phase of the main() function. Let’s see how GCC handles that:
    Code:
    #zeroing out some of the registers
    li      r0,0
    mr      r3,r0
    #Here we increment the Stack Pointer, thus getting rid of main()’s stack even its data
    addi    r11,r31,32 
    #Here we get back our previous LR (the address)
    lwz     r0,4(r11)
    #and we move it into the actual LR
    mtlr    r0
    #get the previous Frame Pointer (SP) from the main()’s stack, although we raised the stack #pointer already, the data wasn’t overridden.
    lwz     r31,-4(r11)
    #and we store the SP in r1
    mr      r1,r11
    #branch out of here, probably into the finalization and then into the program destructor
    blr
    Summary:

    So let’s see what we know about main():

    Stores argv and argc on the stack.
    Calls initialize() and player_guess().
    Loads in the game_number and guess and compares them if they’re equal if not then the Program Counter jumps back and calls player_guess() again.
    Else it writes out the Contratulations message with the game_number and then the program ends.

    This is vital info in reverse engineering this small program (not that you would need to reverse engineer something as simple as this xD).

    So now that we know what main() does then let’s look at initialize() and player_guess(). I won’t break the code down like I previously did. I’m going to just comment it and when something special comes up, then I’ll make a more detailed explanation:
    Code:
    #initialize() starts here
    <initialize>:
            #Prologue
            #Create stack, about 32 Bytes
            stwu    r1,-32(r1)
            #move LR in to r0
       mflr    r0
            #store LR to previous code into the previous stack
       stw     r0,36(r1)
       #store old Frame Pointer on SP+28
       stw     r31,28(r1)
       #move new Frame Pointer into r31
       mr      r31,r1
       #Program Code:
            #10000a80 points to the following string: “Welcome to the Guessing game!”
            #this gets displayed by puts()
       lis     r0,4096
       addic   r3,r0,2688
       bl      10000960 <puts@plt>
            #Call time() with 0 as the first argument
       li      r3,0
       bl      10000940 <time@plt>
       #Load the result into r0, this is one worthless instruction here
       #deleting it would make the program execute faster
       mr      r0,r3
            #move result back into r3 again, worthless :-/ the result is moved into r3              
            #automatically and you don’t need to move around it between r0 and r3
       mr      r3,r0
            #Call srand() with the result from time(), stored on r3
       bl      10000900 <srand@plt>
            #Call rand(), no arguments this time
       bl      10000970 <rand@plt>
       #move the result from r3 into r9
       mr      r9,r3
       #this is what the MODULO operator generates
       #no wonder why developers call it “expensive”, look at all these instructions:
       lis     r0,26214 #Load 0x6666 into r0
       ori     r0,r0,26215 #Or it with 0x6667 to generate 0x66666667
       #Remember that r9 stores the random number
       #mulhw stands for “Multiply High Word”, 
            #signed integers inside r9 and r0 form a 64 bit result
            #the high word of this product is placed into r0, the result is a signed integer
       mulhw   r0,r9,r0 
       #I think I’ll leave the rest to you, it’s interesting to find out how the MODULO
       #operator works in low level, but we are really not interested in it at the moment
       #shift algebraic word by immediate
       srawi   r11,r0,2
       srawi   r0,r9,31
       #subtract from, where we subtract from r11 by r0 and place the result into r0
       #check out the 6xx_pem.pdf for more information
       subf    r0,r0,r11
       rlwinm  r0,r0,1,0,30
       rlwinm  r11,r0,2,0,29
       add     r0,r0,r11
       subf    r0,r0,r9
            #The generated number resides in r9 we also add 1 to the random number to make 
            #it between 1 and 10, notice Add Immediate with Carry
       addic   r9,r0,1
    Here’s a little help on recognizing MODULO in any future projects. I’ve managed to create a program which consists of the following code:
    Code:
    /*modulo.c*/
    #include <stdio.h>
    
    int main()
    {
       int operand_1 = 50;
       int operand_2 = 100;
       double result = 0;
       result = operand_1 % operand_2;
       
       return 0;
    }
    The example code is very simple. We are creating static data on the stack, 2 Integers and a double. The double stores the result. That means we will see some use of the float instructions and the floating point registers. Let’s look at the screenshot I made after disassembling the ELF with objdump:



    Notice one important thing. We can see what the operands are and how the MODULO code uses them. This can be helpful in recognizing operands in our PPU_guessing example.

    We can see the +1 immediate in the end and the result of rand() stored on r9. The only thing we can’t spot is the 10 immediate which we are “dividing” with (Notice rand() % 10 in the source code of PPU_guessing.)
    Code:
       
            #Display information
       #1001102c points to game_number
       lis     r0,4097
       mr      r11,r0
       #But this time we are not loading the value but instead store r9 on the this address
       #which means the randomly generated number gets stored inside game_number
       stw     r9,4140(r11)
       #0x10000aa0 points to the following string:
            #“A random number was generated between 1 to 10 for you.”
       lis     r0,4096
       addic   r3,r0,2720
       #we write out the message using the above address using puts()
       bl      10000960 <puts@plt>
       #Increment the Frame Pointer to get out of this stack
       addi    r11,r31,32
       #load back the old LR
       lwz     r0,4(r11)
       #load r0 (old LR address) into the LR
       mtlr    r0
       #load back the old Frame Pointer
       lwz     r31,-4(r11)
    #move it into r1
       mr      r1,r11
       #branch and link out of this stack and back into main()
       blr
    If you are asking “How the hell did you find out that those instructions were actually the MODULO operator?”. This is when experience starts to kick in. If you had checked out a C source code (compiled with GCC) that uses the MODULO, you would’ve known that those instructions are indeed “hiding” a MODULO operator. From now on always check the assembly source code your compiler is generating. Then try and understand it. It’s easier if you have the C source code. But without the source code you can only rely on your own knowledge.

    Summary:

    So here’s what we know about initialize():

    Writes a welcome message.
    Uses time(), srand(), rand() and the MODULO operator (% in C) to generate a random number between 1 to 10
    Stores the random number as game_number (on game_number’s address)
    Writes out a message that the number was generated between 1 to 10

    Next up, we have the player_guess() function. What we already know about player_guess() is that it probably asks the player to input values. Let’s see how this is done:
    Code:
    #player_guess() starts here:
    <player_guess>:
       #Prologue:
       #Set up stack, about 32 Bytes
    stwu    r1,-32(r1)
    #move LR into r0
       mflr    r0
       #store LR on the old stack (main())
    stw     r0,36(r1)
    #store old Frame Pointer on SP+28
    stw     r31,28(r1)
    #FP = SP
    mr      r31,r1
    #0x10000Ad8 points to “Please place your bet: ”
    lis     r0,4096
    addic   r0,r0,2776
    mr      r3,r0
    #clear cr1’s EQ bits
    crclr   4*cr1+eq
    #Call printf() to write the string we mentioned: “Please place your bet: ”
    bl      10000930 <printf@plt>
    #0x10000AF0 points to “%d”, integer data
    lis     r0,4096
    addic   r0,r0,2800
    mr      r3,r0
    #0x10011030 points to a data in .sbss, this one is actually a data known as guess
    lis     r0,4097
    addic   r4,r0,4144
    #clear EQ bits in cr1
    crclr   4*cr1+eq
    #so here the program reads the data from the user, using scanf()
    bl      10000950 <__isoc99_scanf@plt>
    #Loads in the data at address 0x10011030 (guess) into r9
    lis     r0,4097
    mr      r11,r0
    lwz     r9,4144(r11)
    # r0 gets the data at address 0x1001102c (game_number)
    lis     r0,4097
    mr      r11,r0
    lwz     r0,4140(r11)
    #compare words, r9 and r0 and store the result inside cr7, in other words
    #compares game_number and guess
    cmpw    cr7,r9,r0
    #Predicted Branch into address 0x10000754(check if greater than) if r9(guess) is less
    #than r0(game_number)
    #or equal to, predicted not to be taken, notice the ‘bne-‘ 
    ble-    cr7,10000754 <player_guess+0x8c>
    #if r9(guess) is not less than or equal to r0(game_number),which could mean that it is
    #greater than game_number, then we proceed in this direction: 
    lis     r0,4096
    #r9 stores 0x10000AF4 which points to this string:” Nah, sorry you missed it! The         #number you are looking for is actually SMALLER than %d/n”
    #Don’t be confused about the message, the program wants you to input a smaller 
    #number, cause the one you gave in is just too big.
    addic   r9,r0,2804
    lis     r0,4097
    mr      r11,r0
    #r0 stores the address 0x10000030 which points to ‘guess’ data
    lwz     r0,4144(r11)
    #move string(“Nah, sorry you missed it...”) into r3 (first argument) of printf()
    mr      r3,r9
    #move data(guess) into r4 (second argument) of printf()
    mr      r4,r0
    #clear EQ bits inside cr1, interesting the system seems to do this all the time
    #when it calls printf(), probably uses this as a ‘No Operation’ ???
    #we could actually check if printf() uses cr1’s EQ bits for something interesting
    #just dig into printf() ? 
    crclr   4*cr1+eq
    bl      10000930 <printf@plt>
    #branch unconditionally into the address at 0x10000798 (which is the Epilogue)
    #which means we destroy this stack and then recreate it once main() tells the machine
    #to branch back to this function (player_guess())
    b       10000798 <player_guess+0xd0>
    
            10000754: lis     r0,4097
          mr      r11,r0
                #Load in 0x10011030 (guess) into r9
          lwz     r9,4144(r11)
          lis     r0,4097
          mr      r11,r0
          #Load in 0x1001102c (game_number) into r0
          lwz     r0,4140(r11)
          #Compare words r9 and r0 and store the result in cr7
          cmpw    cr7,r9,r0
                #Predicted Branch if r9 (guess) is greater than or equal to r0 
                #(game_number), branch is predicted not to be taken, if taken then we 
                #branch to this address: 0x10000798 (Epilogue)
                bge-    cr7,10000798 <player_guess+0xd0>
                #if r9(guess) is not greater than r0(game_number)
          lis     r0,4096
          #Load address of string into r9:“Nah, sorry you missed it! The number your 
          #looking for 
          #is actually LARGER than %d”
          addic   r9,r0,2888
          lis     r0,4097
    mr      r11,r0
          #Load address of data into r0: guess (data)
          lwz     r0,4144(r11)
          #The string address goes into r3 (first argument) 
          mr      r3,r9
          #The data address goes into r4 (second argument)
          mr      r4,r0
          #Again we clear the EQ bits inside cr1 cause we are calling printf()
          crclr   4*cr1+eq
          bl      10000930 <printf@plt>
    
    0x10000798: #Epilogue:
          #Increment the SP to delete the current Stack
          addi    r11,r31,32
          #load in previous return address
          lwz     r0,4(r11)
          #load previous return address into the LR
          mtlr    r0
          #load previous SP into the Frame Pointer
          lwz     r31,-4(r11)
          #pass SP to r1
          mr      r1,r11
          #branch back to main()
          blr
    Summary:

    So what do we know about player_guess?:

    player_guess() asks the player to input an integer. It doesn’t check the size of the number! But it doesn’t matter cause, you can’t input anything larger than what an integer can hold. If you input a character or a string then the program goes into an infinite loop. So no character or string check as well. So the data is being read by scanf(%d).
    After that the program compares game_number and guess. If guess is less than or equal to game_number then the program checks if guess is actually larger than or equal to game_number if the two numbers are equal then we branch and link out of this function. The code to check if game_number and guess are equal is in the main() function.

    We can consider this as a big bottleneck to performance cause, the Stack has to be rebuilt each time the player inputs the wrong number. It would be better to not to use a function for this rather copy the code into main().
    We’ve managed to find out how the program works exactly by looking at its PPU assembly code. The information we’ve gathered is enough to rebuild this program or to view its flaws. We can also rewrite the whole program in C if we really want to. Yeah I know that the MODULO section was pretty tricky but if you view the assembly code your compiler generates then you’ll be able to spot things like these easily. Keep viewing PPU code and you’ll be able to reverse anything you want.

    Our next section will talk about reversing SPU code.

    Reversing Cell SPU code

    Now that we know how to use spu-gdb, spu-objdump and spu-readelf, we should move on to reversing our sample program. There are not too many articles or tutorials about reversing actual SPU code (actually I wasn’t able to find any but I’m sure you guys will prove me wrong). So this part of my tutorial might be very interesting for newcomers to SPU assembly language and reversing.

    So as I mentioned before in the prologue section of this tutorial (nah, not the prologue section where we setup the stack ). Open up the docs SPU ISA and SPU assembly language specification. Don’t worry you don’t have to actually read these documents from the beginning to the end. We are actually going to work with these documents when we are reversing our code. You can download these pdf’s or just use the online version from IBM.

    Alright I hope you are well rested cause, we are going deep into SPU code today. SPU code is a lot easier to reverse using objdump cause, you can view the data right away, and you don’t have to calculate the addresses. Also the addresses you need to load into your registers are smaller numbers and you don’t have to combine them. The LS can only store about 256 KBs of data. This means, if you want more memory, then you need to use MFC DMA to access the main memory. Using MFC DMA isn’t easy to use. You need to use 2^4 byte alignment and use some special function calls in order to send and receive data from the MFC DMA traffic. Our example program doesn’t handle this but you can try and write something that utilizes this fantastic feature of the CELL/BE or check out the tutorials I mentioned above.

    Let’s cut the chit-chat and look at the code we have here. Oh I almost forgot, we haven’t used objdump to view the code, so here are the magic words you need to use:
    Code:
    spu-objdump –D –j .text SPU_guessing
    As we did previously, I’m going to run and explain most of the sections we won’t be touching when we are reversing the program. I will only list the parts we won’t be touching. I won’t be commenting the ones that were already commented in the PPU section. Here we go:
    Code:
    _start
    __do_global_dtors_aux
    call__do_global_dtors_aux
    frame_dummy
    call_frame_dummy
    atexit
    exit
    printf: sent to the PPE (not called directly by the SPU)
    puts: sent to the PPE
    srand: sent to the PPE
    rand: sent to the PPE
    scanf: sent to the PPE
    __stack_reg_va
    reg_4
    reg_3
    save_regs_1
    save_regs_2
    time: calls gettimeofday()
    __register_exitproc
    __call_exitprocs
    _exit
    gettimeofday: sent to PPE
    __send_to_ppe:
    “This performs the assembly language magic needed to stop the SPE, signal the PPE, and pass a single argument. __send_to_ppe is called with three arguments:
    • The first one is the signal to send to the PPE. PPE callbacks begin with the hex digits 21 and the next two hex digits refer to the callback number being called.
    • The second argument is used for callbacks that code multiple functions and basically serves to allow the callback function to switch functionality based on the value. This value basically gets plugged into the high-order byte of the data pointer. Most simple applications just use 0 for this argument.
    • The third argument is the data (usually a pointer) to pass to the PPE. Remember, however, that the high-order byte of the third parameter gets replaced with the value of the second parameter when the system actually passes the arguments.”

    Taken from: [Register or Login to view links]
    Code:
    __muldi3
    __do_global_ctors_aux
    call __do_global_ctors_aux
    As you can see the C runtime functions are actually passed to the PPE. The SPU doesn’t call them directly. Interesting mechanism, isn’t it?

    The most important parts are as follows:
    Code:
    00000168 <main>:
    168:   24 00 40 80    stqd   $0,16($1)
    16c:    24 fe c0 81    stqd   $1,-80($1)
    170:   1c ec 00 81    ai   $1,$1,-80
    174:   34 00 80 82    lqd   $2,32($1)   # 20
    178:   3e e0 00 86    cdd   $6,0($1)
    17c:    b0 40 81 86    shufb   $2,$3,$2,$6
    180:   24 00 80 82    stqd   $2,32($1)   # 20
    184:   34 00 c0 82    lqd   $2,48($1)   # 30
    188:   3e e0 00 83    cdd   $3,0($1)
    18c:    b0 40 82 03    shufb   $2,$4,$2,$3
    190:   24 00 c0 82    stqd   $2,48($1)   # 30
    194:   34 01 00 82    lqd   $2,64($1)   # 40
    198:   3e e0 00 83    cdd   $3,0($1)
    19c:    b0 40 82 83    shufb   $2,$5,$2,$3
    1a0:    24 01 00 82    stqd   $2,64($1)   # 40
    1a4:    34 00 80 82    lqd   $2,32($1)   # 20
    1a8:    23 82 0b 02    stqr   $2,1200 <host>   # 1200
    1ac:    33 00 08 80    brsl   $0,1f0 <initialize>   # 1f0
    1b0:   33 00 25 00    brsl   $0,2d8 <player_guess>   # 2d8
    1b4:   33 82 0b 82    lqr   $2,1210 <guess>   # 1210
    1b8:   33 82 07 03    lqr   $3,11f0 <game_number>   # 11f0
    1bc:    78 00 c1 02    ceq   $2,$2,$3
    1c0:    20 7f fe 02    brz   $2,1b0 <main+0x48>   # 1b0
    1c4:    42 06 28 03    ila   $3,3152   # c50
    1c8:    33 00 45 00    brsl   $0,3f0 <puts>   # 3f0
    1cc:    33 82 04 82    lqr   $2,11f0 <game_number>   # 11f0
    1d0:   42 06 40 03    ila   $3,3200   # c80
    1d4:   04 00 01 04    ori   $4,$2,0
    1d8:   33 00 3d 00    brsl   $0,3c0 <printf>   # 3c0
    1dc:    40 80 00 02    il   $2,0
    1e0:    04 00 01 03    ori   $3,$2,0
    1e4:    1c 14 00 81    ai   $1,$1,80   # 50
    1e8:    34 00 40 80    lqd   $0,16($1)
    1ec:    35 00 00 00    bi   $0
    
    000001f0 <initialize>:
    1f0:    24 00 40 80    stqd   $0,16($1)
    1f4:    24 ff 80 81    stqd   $1,-32($1)
    1f8:    1c f8 00 81    ai   $1,$1,-32
    1fc:    42 06 58 03    ila   $3,3248   # cb0
    200:   33 00 3e 00    brsl   $0,3f0 <puts>   # 3f0
    204:   33 81 ff 82    lqr   $2,1200 <host>   # 1200
    208:   42 06 68 03    ila   $3,3280   # cd0
    20c:    04 00 01 04    ori   $4,$2,0
    210:   33 00 36 00    brsl   $0,3c0 <printf>   # 3c0
    214:   40 80 00 03    il   $3,0
    218:   33 00 77 00    brsl   $0,5d0 <time>   # 5d0
    21c:    04 00 01 82    ori   $2,$3,0
    220:   04 00 01 03    ori   $3,$2,0
    224:   33 00 41 80    brsl   $0,430 <srand>   # 430
    228:   33 00 47 00    brsl   $0,460 <rand>   # 460
    22c:    40 80 05 02    il   $2,10
    230:   35 90 00 00    hbrp   230 <initialize+0x40>,$0
    234:   35 90 00 00    hbrp   234 <initialize+0x44>,$0
    238:   7f 00 01 00    heqi   $0,$2,0
    23c:    12 00 08 9a    hbrr   2a4 <initialize+0xb4>,280 <initialize+0x90>   # 280
    240:   0c 00 01 8a    sfi   $10,$3,0
    244:   0c 00 01 0b    sfi   $11,$2,0
    248:   4c ff c1 8c    cgti   $12,$3,-1
    24c:    4c ff c1 0d    cgti   $13,$2,-1
    250:   81 40 c5 0c    selb   $10,$10,$3,$12
    254:   81 60 85 8d    selb   $11,$11,$2,$13
    258:   54 a0 05 06    clz   $6,$10
    25c:    54 a0 05 89    clz   $9,$11
    260:   40 80 00 87    il   $7,1
    264:   32 80 00 04    fsmbi   $4,0
    268:   08 02 43 09    sf   $9,$6,$9
    26c:    3f e0 05 05    shlqbyi   $5,$10,0
    270:   48 23 46 0d    xor   $13,$12,$13
    274:   0b 62 43 87    shl   $7,$7,$9
    278:   0b 62 45 86    shl   $6,$11,$9
    27c:    00 20 00 00    lnop
    280:   08 21 c2 0e    or   $14,$4,$7
    284:   3f 3f c3 87    rotqmbii   $7,$7,-1
    288:   58 01 43 08    clgt   $8,$6,$5
    28c:    00 20 00 00    lnop
    290:   08 01 43 09    sf   $9,$6,$5
    294:   3f 3f c3 06    rotqmbii   $6,$6,-1
    298:   80 81 07 08    selb   $4,$14,$4,$8
    29c:    00 20 00 00    lnop
    2a0:    80 a1 44 88    selb   $5,$9,$5,$8
    2a4:    21 7f fb 87    brnz   $7,280 <initialize+0x90>   # 280
    2a8:    0c 00 02 8a    sfi   $10,$5,0
    2ac:    0c 00 02 0b    sfi   $11,$4,0
    2b0:   80 a1 45 0c    selb   $5,$10,$5,$12
    2b4:   80 82 c2 0d    selb   $4,$4,$11,$13
    2b8:   04 00 02 82    ori   $2,$5,0
    2bc:    1c 00 41 02    ai   $2,$2,1
    2c0:    23 81 e6 02    stqr   $2,11f0 <game_number>   # 11f0
    2c4:    42 06 80 03    ila   $3,3328   # d00
    2c8:    33 00 25 00    brsl   $0,3f0 <puts>   # 3f0
    2cc:    1c 08 00 81    ai   $1,$1,32   # 20
    2d0:   34 00 40 80    lqd   $0,16($1)
    2d4:   35 00 00 00    bi   $0
    
    000002d8 <player_guess>:
    2d8:   24 00 40 80    stqd   $0,16($1)
    2dc:    24 ff 80 81    stqd   $1,-32($1)
    2e0:    1c f8 00 81    ai   $1,$1,-32
    2e4:           42 06 a0 03    ila   $3,3392   # d40
    2e8:           33 00 1b 00    brsl   $0,3c0 <printf>   # 3c0
    2ec:           42 06 b0 03    ila   $3,3424   # d60
    2f0:           42 09 08 04    ila   $4,4624   # 1210
    2f4:           33 00 3f 80    brsl   $0,4f0 <scanf>   # 4f0
    2f8:           33 81 e3 02    lqr   $2,1210 <guess>   # 1210
    2fc:           33 81 de 83    lqr   $3,11f0 <game_number>   # 11f0
    300:   48 00 c1 02    cgt   $2,$2,$3
    304:   20 00 03 02    brz   $2,31c <player_guess+0x44>   # 31c
    308:   33 81 e1 02    lqr   $2,1210 <guess>   # 1210
    30c:           42 06 b8 03    ila   $3,3440   # d70
    310:   04 00 01 04    ori   $4,$2,0
    314:   33 00 15 80    brsl   $0,3c0 <printf>   # 3c0
    318:   32 00 04 80    br   33c <player_guess+0x64>   # 33c
    31c:    33 81 de 82    lqr   $2,1210 <guess>   # 1210
    320:   33 81 da 03    lqr   $3,11f0 <game_number>   # 11f0
    324:   48 00 81 82    cgt   $2,$3,$2
    328:   20 00 02 82    brz   $2,33c <player_guess+0x64>   # 33c
    32c:           33 81 dc 82    lqr   $2,1210 <guess>   # 1210
    330:   42 06 e8 03    ila   $3,3536   # dd0
    334:   04 00 01 04    ori   $4,$2,0
    338:   33 00 11 00    brsl   $0,3c0 <printf>   # 3c0
    33c:           1c 08 00 81    ai   $1,$1,32   # 20
    340:   34 00 40 80    lqd   $0,16($1)
    344:   35 00 00 00    bi   $0
    Notice that we are using $ (Dollar) to tell the programmer that he’s looking at a register.

    The ABI is pretty much the same as with the PPU. We have $0 which stores the current LR (Link Register or Back Chain Pointer). $1 stores the SP (Stack Pointer). $2 stores the environment pointer, which is used by some programming languages. $3 to $74 are used as arguments. $3 is the register that stores the returned result. We can safely assume that we won’t be storing any arguments on the stack that’s for sure with this many registers.



    After the listing I guess we should take a look at the code more closely:
    Code:
    <main>:
    As always SPU-GCC makes a label for main().

    Prologue:
    Code:
    stqd   $0,16($1)
    stqd   $1,-80($1)
    ai        $1,$1,-80
    Very standard. We store the LR on the previous stack (_start). stqd stands for store quad word (D-form). I haven’t really mentioned the addressing forms yet. But in SPU assembly you are almost always telling the assembler explicitly which addressing mode you are using. Unlike PPU assembly where you just use what you like when storing or loading. The D-Form is very simple basically you are adding an immediate to the register. Here we are adding 16 to $1 (register 1, which stores the SP). $0 stores the LR of course. These two are dedicated registers. Since this is a store command it means that we are storing $0 on SP+16. Notice how we store the previous SP (Stack Pointer) at the bottom of the stack. Then we create the 80 bytes long stack by decrementing the SP (Stack Pointer) in $1. Unlike in PPU assembly in SPU assembly you cannot store something or load and then update the registers. So here you need an extra Add Immediate (ai) to decrement the SP.

    Program Code:
    Code:
    lqd     $2,32($1)   # 20
    cdd     $6,0($1)
    shufb   $2,$3,$2,$6
    stqd   $2,32($1)   # 20
    Here is something very interesting. The first instruction loads in data from SP+32 and moves it into $2 then creates a control for word insertion. Basically this can be used to mask off unwanted bits. The next instruction shuffles $3 and $2 using $5 as control bit and stores the result in $2. This way we are moving every bit into the so called preferred slots. This is an important part. If the data isn’t aligned this way then you’ll get false data or so called data corruption. In order to counter that, we do the alignment. To understand control bits and bit shuffle refer to the SPU_Assembly_Specification document. Then we store the data back into SP+32.
    Code:
    lqd     $2,48($1)   # 30
    cdd     $3,0($1)
    shufb   $2,$4,$2,$3
    stqd   $2,48($1)   # 30
    The other data gets the same treatment and gets stored back on SP+48.
    Code:
    lqd     $2,64($1)   # 40
    cdd     $3,0($1)
    shufb   $2,$5,$2,$3
    stqd   $2,64($1)   # 40
    Same as before only this time we are storing everything back into SP+64. If you are wondering what these could be then look at the following code:
    Code:
    lqd     $2,32($1)   # 20
    stqr    $2,1200 <host>   # 1200
    Here we can see that we are reading something out of SP+32 and loading it into $2. Then we pass it to a variable on host ‘s address. The three variables SP+32, SP+48 and SP+64 are the arguments which we are storing on the stack. The spe_id, argp and envp. Which means we are storing the spe_id inside host.
    Code:
    brsl     $0,1f0 <initialize>   # 1f0
    brsl     $0,2d8 <player_guess>   # 2d8
    Very familiar instruction sequence. Branch Relative and Set Link is the name of these two instructions. Here we are using them to call 2 functions: initialize() and then player_guess().
    Code:
    lqr   $2,1210 <guess>   # 1210
    lqr   $3,11f0 <game_number>   # 11f0
    ceq   $2,$2,$3
    brz   $2,1b0 <main+0x48>   # 1b0
    ila   $3,3152   # c50
    brsl   $0,3f0 <puts>   # 3f0
    lqr   $2,11f0 <game_number>   # 11f0
    ila   $3,3200   # c80
    ori   $4,$2,0
    brsl   $0,3c0 <printf>   # 3c0
    il   $2,0
    ori   $3,$2,0
    We load guess into $2 and game_number into $3. The third instruction does the comparison and writes the EQ bits into $2. Yeah you are not mistaken. Unlike the PPU, the SPU does not have conditional registers. It uses the “GPRs” for that. The third instruction branches if the result in $2 is Zero. If so then we jump back and call player_guess. If $2 and $3 are not equal, then we branch back. Remember if EQ is set then the two registers are equal, but we are checking for zero, which means we are checking if the two are not equal. After this we load our address (0xc20) of a string into $3. Our string is the following: “Oh goody, you guessed the number!”. After outputting this string with puts(). We are loading in game_number’s address into $2 and a string address (c50) into $3. $4 gets a Zero. Then we can call printf(). Our message will be the following: “the number was indeed %d Congratulations !!!/n”. After that we clear out $2 and $3 and load a Zero inside them.

    If you are interested in where the symbols are for the host, game_number and guess. Check out the .bss (uninitialized data) section using the following command:
    Code:
    spu-objdump –D –j .text SPU_guessing
    You should get the following results. As you can see we have a pointer to the effective address of the LS (Local Store) as well:
    Code:
    000011d0 <completed.4604>:
       ...
    000011e0 <__ea_local_store>:
       ...
    000011f0 <game_number>:
       ...
    00001200 <host>:
       ...
    00001210 <guess>:
       ...
    Epilogue:
    Code:
    ai   $1,$1,32   # 20
    lqd   $0,16($1)
    bi   $0
    Nothing fancy here. We increment the SP ($1) by 64 to destroy the current stack and then load the LR from the previous stack stored at SP+16. Then we use bi to Branch indirectly out of here and end the program.

    Summary

    Let’s summarize what we managed to discover about main(). In general main() is almost the same as we saw in the PPU code. Only this time we are storing SPE_ID inside host and we have 3 arguments which we store on the stack. After that the program calls initialize(). This happens only once. After that we enter a loop where the program keeps asking the player for a number between 1 and 10. The main() loop does the comparison of guess and game_number and branches according to the result. If the two numbers are not the same then the program calls player_guess. If the two values are the same then the program writes out some strings to congratulate the player and the game_number as well. After this the program ends.

    Other Functions:

    Now, we are going to go through the rest of the functions briefly (as we did with PPU_guess):
    Code:
    #initialize() starts here:
    <initialize>:
    
    #PROLOGUE:
    #Store the LR on the previous stack(main()) 
    stqd   $0,16($1)
    #Store SP on the bottom of the new stack
    stqd   $1,-32($1)
    #decrement the SP to create the stack
    ai   $1,$1,-32
    
    #PROGRAM CODE:
    #Load the address of the following string:”Welcome to the Guessing game!” into $3 
    #(first argument)
    ila   $3,3248   # cb0
    #Display string using puts()
    brsl   $0,3f0 <puts>   # 3f0
    #load the address of host into $2, by the way ila stands for load immediate address
    lqr   $2,1200 <host>   # 1200
    #load address of the following string: “Our host for today is SPE number %d!/n” into $3
    #(first argument)
    ila   $3,3280   # cd0
    #writes a zero into $4 (second argument) with $2
    ori   $4,$2,0
    #Print the value and the string out using printf()
    brsl   $0,3c0 <printf>   # 3c0
    #Load zero into $3
    il   $3,0
    #call time() using 0 as argument
    brsl   $0,5d0 <time>   # 5d0
    # write return value of time() into $2 with a zero
    ori   $2,$3,0
    ori   $3,$2,0
    #call srand() with the return value of time(0)
    brsl   $0,430 <srand>   # 430
    #call rand(), no arguments
    brsl   $0,460 <rand>   # 460
    #load 10 into $2 which means we are using MODULO on rand() and dividing it by $2 (10)
    il   $2,10
    As you can see our MODULO operator is back. Here’s the objdump I made of the SPU_Modulo sample program (!) that uses the MODULO operator:



    There are two numbers stored on the stack: operand_1 on SP+64 which has the value of 50 and operand_2 on SP+48 which has the value of 100. The two data are being loaded into registers 2 and 3. this is a big thing cause in the PPU version we weren't able to spot all the operands. If we look at our SPU_guessing, then we can see that we are loading in 10 (immediate) into $2 and the result of rand() is inside $3. On 0x294 address (code) we can see that 1 is being added to the result.

    Code:
    # lots of hint branch calls, bit shifts, masking and subtraction, yes this is the MODULO   
    # operator
    hbrp   230 <initialize+0x40>,$0
    hbrp   234 <initialize+0x44>,$0
    heqi   $0,$2,0
    hbrr   2a4 <initialize+0xb4>,280 <initialize+0x90>   # 280
    sfi   $10,$3,0
    sfi   $11,$2,0
    cgti   $12,$3,-1
    cgti   $13,$2,-1
    selb   $10,$10,$3,$12
    selb   $11,$11,$2,$13
    clz   $6,$10
    clz   $9,$11
    il   $7,1
    fsmbi   $4,0
    sf   $9,$6,$9
    shlqbyi   $5,$10,0
    xor   $13,$12,$13
    shl   $7,$7,$9
    shl   $6,$11,$9
    lnop
    or   $14,$4,$7
    rotqmbii   $7,$7,-1
    clgt   $8,$6,$5
    lnop
    sf   $9,$6,$5
    rotqmbii   $6,$6,-1
    selb   $4,$14,$4,$8
    lnop
    selb   $5,$9,$5,$8
    brnz   $7,280 <initialize+0x90>   # 280
    sfi   $10,$5,0
    sfi   $11,$4,0
    selb   $5,$10,$5,$12
    selb   $4,$4,$11,$13
    ori   $2,$5,0
    #add 1 to the result
    ai   $2,$2,1
    #store the result from $2 into game_number’s address
    stqr   $2,11f0 <game_number>   # 11f0
    #load address of the following string:” A random number was generated between 1 to 10 for 
    #you” into $3 (first argument)
    ila   $3,3328   # d00
    #out put the string above by calling puts()
    brsl   $0,3f0 <puts>   # 3f0
    
    #EPILOGUE:
    #increment the SP to destroy the current stack
    ai   $1,$1,32   # 20
    #load back LR from SP+16
    lqd   $0,16($1)
    #branch into LR (previous code, in main())
    bi   $0
    Summary:

    First thing this function does is that it welcomes the player then writes out which SPE is being used using another message. This function initializes the game. It generates a number between 1 and 10. We can finally read what kind of operands we are dealing with here. After generating the number the program stores it as game_number. So the generated number is actually game_number.
    Code:
    #player_guess() starts here:
    <player_guess>:
    
    #PROLOGUE
    #store LR on the previous stack(main())
    stqd   $0,16($1)
    #store SP on the bottom of the new stack
    stqd   $1,-32($1)
    #decrement the SP to create the new stack
    ai   $1,$1,-32
    
    #PROGRAM CODE:
    #load the address of the following string:”Please place your bet: ” into $3 (first argument)
    ila   $3,3392   # d40
    #we use printf() to write out the string above
    brsl   $0,3c0 <printf>   # 3c0
    #load the address of the following string:” %d” into $3 (first argument)
    ila   $3,3424   # d60
    #interestingly here we don’t see where the data’s address gets loaded from
    #don’t be fooled use the .bss to see what the data is, it’s actually the data named “guess”
    ila   $4,4624   # 1210
    #call scanf()
    brsl   $0,4f0 <scanf>   # 4f0
    #load guess into $2
    lqr   $2,1210 <guess>   # 1210
    #load game_number into $3
    lqr   $3,11f0 <game_number>   # 11f0
    #compare if guess($2) is greater than game_number($3), write the GT bits of $2
    #according to the result
    cgt   $2,$2,$3
    #branch if zero, which means branch if the previous comparison ended with $2 “not greater 
    #then” $3, the address we are branching to is still inside this function (obviously)
    #it’s the part where we load guess and game_number then check if game_number is greater than 
    #guess (0x31c)
    brz   $2,31c <player_guess+0x44>   # 31c
    #if guess was greater than game_number then we do the following:
    #load guess into $2 
    lqr   $2,1210 <guess>   # 1210
    #load the address of the following string:” Nah, sorry you missed it! The number your 
    #looking for is actually SMALLER than %d./n” into $3 (first argument)
    ila   $3,3440   # d70
    #load guess with zero into $4 (second argument)
    ori   $4,$2,0
    #write out the string and the data (guess) using printf()
    brsl   $0,3c0 <printf>   # 3c0
    #Branch to EPILOGUE and exit this function
    br   33c <player_guess+0x64>   # 33c
    
    0x31c:#load guess into $2
              lqr   $2,1210 <guess>   # 1210
             #load game_number into $3
         lqr   $3,11f0 <game_number>   # 11f0
            #compare if game_number is greater than guess
         cgt   $2,$3,$2
       #if game_number is not greater than guess, then the two values are probably equal 
            #and we branch to EPILOGUE to exit this function, remember that we are checking if the 
            #two values are not equal
         brz   $2,33c <player_guess+0x64>   # 33c
            #if the two are not equal and it turns out that game_number is greater than guess:
         #we load guess into $2
         lqr   $2,1210 <guess>   # 1210
         #load the following string:” Nah, sorry you missed it! The number your looking for is 
              #actually LARGER than %d./n” into $3 (first argument)
              ila   $3,3536   # dd0
              #write guess with zero into $4 (second argument)
           ori   $4,$2,0
         #call printf() to write out the data(guess) with the message above
         brsl   $0,3c0 <printf>   # 3c0
    0x33c:  #EPILOGUE
                 #increment the SP to destroy the current stack
                  ai   $1,$1,32   # 20
           #Load old LR 
            lqd   $0,16($1)
                #branch back to main()
            bi   $0
    Summary:

    The player_guess() does some of the logical decisions of the program, but not all of them. It asks for a number (no limits) and then compares it with game_number. If guess is greater than game_number, then we write out that guess was too large and the number we are looking for is smaller. After that the program destroys the stack and goes back to main(). Where it jumps back to the player_guess and creates the stack again. (What a waste, this logic should be inside main(). The problem is the same as with the PPU_guessing program.) But if guess is not greater than game_number then we check if guess is smaller than game_number. If so then we write out that the number we are looking for is larger than guess. If not then we exit from the function directly. Meaning that the two values are probably equal and main() will check that separately.

    Right, we are done reversing.

    When we fail miserably - I bumped into several problems during the time I wrote this tutorial. It appears that using objdump on PPC64 code which is compiled with the “-dynamic” flag (normally if you don’t ask for “–static” explicitly then you get dynamic code) you can’t tell which function from the dynamically linked object file is being called. The problem is that some function calls like the libc functions get resolved dynamically. Which means you can’t determine what kind of function call was made. You only get redirected to .glink PLT resolver code which makes no sense to mere humans. The .got doesn’t store an absolute address to these calls which brings us back to the problem I mentioned in the last sentence. What can we do then? How can we use objdump to reverse PPC64 code? …Honestly? Use IDA. There’s really no other way. You can try and guess what the calls could be. Also the addresses to data are negative numbers which make no sense what so ever. The following commands could help you with PPC64 code (but I think PPC64 is just hopeless as it gets with objdump):
    Code:
    objdump –R <File_Name> // shows relocations in the ELF file
    ldd <File_Name> // view dependencies in your ELF
    nm <File_Name> // allows you to view symbols in your ELF
    The above commands can help you finding out the name of the functions and methods being called.
    Also check out the following article on dynamic linking and ELF files: [Register or Login to view links]

    This is the command I tried to use to disassemble the PPC64 bit code:
    Code:
    objdump –D –j .text PPU_guessing
    This is also possible:
    Code:
    ppu-objdump –D –j .text PPU_guessing
    Maybe if you try and play around with the Machine or Architecture settings you might get the function names as well. I tried everything even following the code but I haven’t been able to solve this mystery. Good luck!

    Conclusion

    That’s it for now folks. If anyone has questions, then please post them on this thread so I can take a look. It was actually pretty hard and time consuming to write this tutorial. I hope it shed some light on a few mysteries about reverse engineering code. Remember we’ve only touched basic code with symbols turned on. In most cases you don’t have this comfort. You need to recognize C runtime functions your self and you cannot rely on symbols. Also C++ code is another thing to reverse. It can be really painful. Just keep looking at assembly code and you’ll get better. Also you might want to try and compile your code with the following parameters:
    Code:
    GCC <Source_Code.c> -S <Destination_Assembly code.s>
    SPU-GCC <Source_Code.c> -S <Destination_Assembly_code.c>
    This will output you the assembly source code of your C program. This assembly source code can be very helpful in understanding what the compiler did with your C code. The binary we were examining was already linked and contained text and data which we were not interested in. This parameter gives you the program code only. Have fun with your new toys and if you have questions then please don't keep them to yourself.

    Guide to Reversing on PS3 Linux Using the GNU Toolchain

    More PlayStation 3 News...
    Attached Images<br><br> Attached Images


  2. #2
    Registered User tjay17's Avatar
    Join Date
    Apr 2010
    Posts
    421
    Sponsored Links
    Sponsored Links
    What can you do with this?

  3. #3
    Forum Moderator PS3 News's Avatar
    Join Date
    Apr 2005
    Posts
    27,455
    Sponsored Links
    Sponsored Links
    Honestly, it's just for budding Devs who wish to learn how to reverse-engineer... most end-users probably won't ever use it.

  4. #4
    Registered User red8316's Avatar
    Join Date
    Feb 2009
    Posts
    205
    Sponsored Links
    Sponsored Links
    Wowza, lots of information, very comprehensive post. Looks like a useful contribution. Nice work.

  5. #5
    Registered User duventj's Avatar
    Join Date
    Aug 2005
    Posts
    4
    Interesting and very nice post...

    Merci beaucoup !!

 

Sponsored Links

Affiliates - Contact Us - PS3 Downloads - Privacy Statement - Site Rules - Top - © 2014 PlayStation 3 News