Manipulate the return address of a C function

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
captainwiggles
Posts: 23
Joined: Tue Nov 11, 2008 3:03 pm

Re: Manipulate the return address of a C function

Post by captainwiggles »

can you rephrase that last bit? I'm not entirely sure what your asking.

And yes you are right, IRET has different behaviour when it returns to kernel mode.

According to the intel docs, IRET pops off the eip, cs and eflags (in that order) and then if we are changing privalidge level, it also pops the useresp and ss.

This occured to me earlier, but i was assuming you where doing usermode stuff rather than not.

You can't just remove the useresp and ss values, since you do want to change stack, so just push the esp and ss to the stack and pop them as required.

Code: Select all

_isr0:
    cli   

    push esp
    push ss
                      
    push byte 0                 ; Push a dummy error code.
    push byte 0                   ; Push the interrupt number.

    pusha                       ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

    call _isr_c_timer

    popa                        ; Pops edi,esi,ebp...
    add esp, 8           ; Cleans up the pushed error code and pushed ISR number

    pop ss
    pop esp

    sti

    IRET

note, when we pop esp, we will have the same stack as before, hence the same eip as when the interrupt was called, which is fine, however you have to be carefull when modifying useresp in the registers struct, since changing it will change what stack it goes back to, and since the eip and things are on the original stack, they will also be different.

This is an issue when you create a thread now, as you will go to the new stack, then pop off eflags, cs and eip, which of course arn't on the new stack already.

So you have to put them there.

Code: Select all

void create_thread(void (*entry)(), u32int stack) {
   registers_t t = registers[current_thread];
   t.eip = entry;

    //add the end_task method to the stack
   stack -=4
   *((u32int*)t.useresp) = end_task;

    //add the eip, cs and eflags to the stack
    stack-=4;
   *((u32int*)stack = entry;
   stack-=4;
   *((u32int*)stack = t.cs;
   stack-=4;
   *((u32int*)stack = t.eflags;

   //now set the user stack to stack
   //so when it pops off into esp there is the right values there
   t.useresp = stack;

  //now the new stack has eflags, cs, eip, end_task on it, in that order.
  //the _isr0 code pops ss, esp off the current stack, giving the new stack
  //iret pops eflags, cs, eip off the new stack, leaving just end_task
  //when the thread returns, end_task should be called.

   registers[thread_count++] = t;
}
So .. I think this will work, it'll prob have some bugs in, but i think the principle is sound, sorry its so complex, there may be a simpler solution, but i can't see it yet.

Also sorry about the lengthiness and wordiness and probable incoherancy of this post, I came up with the solution as I went, I hope you understand it.
mangaluve
Member
Member
Posts: 110
Joined: Mon Feb 23, 2009 6:53 am

Re: Manipulate the return address of a C function

Post by mangaluve »

Thanks man! I'll try that as soon as I get home from work :) Thanks a lot!

I tried the code you provided and it worked perfectly with some minor modifications..finally! thanks a lot!
captainwiggles
Posts: 23
Joined: Tue Nov 11, 2008 3:03 pm

Re: Manipulate the return address of a C function

Post by captainwiggles »

any luck?
Post Reply