stack

osusec

monday, 1/13

Capture The Flag League

the stack

  • pizza
  • streaming
  • unmuted
  • cd’d into the right directory

some computer science

what’s a stack

  • simple data structure
  • push a value to the end
  • pop a value off the end

whatever for?

imagine a program

3 4 +

u can guess what that does

adds 3 and 4
how tho?

with a stack :)

  • read a digit? push to stack
  • read a mathy symbol? pop two values from the stack and math them

stack trace:

3 4 +

3
3 4
7

more

4 3 4 + *

4
4 3
4 3 4
4 7
28

last one

4 3 4 + * 3 +

4
4 3
4 3 4
4 7
28
28 3
31

you may have noticed

our programs (3 4 +) are just ways of manipulating a stack
and a stack is just kind of like scratch space to put numbers for later use.
and digits are just arguments to functions

we can write pseudo-asm:

push 4              [4]
push 3              [4, 3]
push 4              [4, 3, 4]
add                 [4, 7]
multiply            [28]
push 3              [28, 3]
add                 [31]

functions

as code gets more complex, we like to write functions/subroutines. reusable, flexible pieces of code.

this might look something like

push 3          [3]
call square     [9]
call square     [81]

(inside square we’ve got some code that squares a number)

yes, but

  1. how does our program get back to the next line of code to where it was once square completes?

  2. square might need to use the stack too - how do we make sure the function that calls it will know where the stack is?

  3. how are we keeping track of all this stack stuff in the first place

i tried really hard to cleanly connect this intro to what we’re about to do but the best I can come up with is asking these questions

so keep these in mind as we move into a C program

the answer to all of these questions is registers, by the way.

saving registers. restoring registers. registers registers registers.

what’s it like to hold the hand of someone you love? registers. have they left a place for you where you can dream? registers.

ugly ugly bring in terminal pls

int square(int num) {
   0x0000116d <+0>:     push   ebp
   0x0000116e <+1>:     mov    ebp,esp

return num * num;
   0x00001170 <+3>:     mov    eax,DWORD PTR [ebp+0x8]
   0x00001173 <+6>:     imul   eax,eax
   0x00001176 <+9>:     pop    ebp
}
   0x00001177 <+10>:    ret
int main() {
   0x00001178 <+0>:     push   ebp
   0x00001179 <+1>:     mov    ebp,esp
   0x0000117b <+3>:     sub    esp,0x10

int my_fun_variable = 3;
   0x0000117e <+6>:     mov    DWORD PTR [ebp-0x4],0x3
square(my_fun_variable)
   0x00001185 <+13>:    push   DWORD PTR [ebp-0x4]
   0x00001188 <+16>:    call   0x116d <square>

   0x0000118d <+21>:    add    esp,0x4 // for alignment

square(square(my_fun_variable))
   0x00001190 <+24>:    push   eax
   0x00001191 <+25>:    call   0x116d <square>

int even_funner = square(square(my_fun_variable))
   0x00001196 <+30>:    add    esp,0x4 // alignment
   0x00001199 <+33>:    mov    DWORD PTR [ebp-0x8],eax

}
   0x0000119c <+36>:    mov    eax,0x0
   0x000011a1 <+41>:    leave
   0x000011a2 <+42>:    ret

idiot-proofing:

  • show source
  • disass main
  • disass square
  • stack -f

this is insane

ebp, esp, DWORD PTR, eax, call, ret

but it’s solving all our problems!

what do call and leave and ret do?

a stack frame

we mark where our stack was when we entered a function, and it gives us a stable peg to base new stack entries off of.

(this is because it’s nice to have access beyond push/pop. from now on, when I say stack, i really mean The Stack, which is not exactly a stack.)

push ebp
mov ebp,esp

saves the parent function’s “base pointer” to the stack
and copies the current stack pointer into the base pointer register

next

main is kinda weird because the thing that calls main has a base pointer of 0. anyways we’ll get back into it in a second.`

next up is

mov    DWORD PTR [ebp-0x4],0x3
push   DWORD PTR [ebp-0x4]
call   0x8049156 <square>

what that mean

mov loads 3 into a local variable, located 4 above ebp
parameters are pushed to the stack
and then we call 0x8049156

call moves our instruction pointer eip to a new place in memory… and something else >:3

eip is a little guy that walk around memory and tells the CPU what instruction to fetch and execute

let’s look at the less insane square function

  • reminder for paul to really examine the stack

you might have noticed

  1. square just has pop ebp, no leave this works because the stack isn’t really used in square
    leave is shorthand for mov esp,ebp , pop ebp

  2. there are random blank/unused spots on the stack yeah, compilers like to do that.

putting it all together

  • call pushes $eip and jumps to a new address
  • leave pops the saved $ebp into $esp
  • ret pops a return address into $eip
  • parameters are below (larger addressed than) the base pointer
  • return value is in $eax

pwntools 4 tn

template in description, but we here to help p32() is ur friend!

might be necessary?

sudo dpkg –add-architecture i386 sudo apt-get update