1

EDIT: thank alot

Im understanding now that I should use gdb

I ask for understand how stack frame working and how change things

exit(0) and goto its not option

How can change that fun 'sec' will return to main? the output will be:

print start main
print this from first
print this from sec
print exit main
void sec() 
{
    
   /*change only here */
   printf("print this from sec");
}
void first() 
{
    printf("print this from first");
    sec();
    printf("dont print this");
}
 
int main() {
    
    printf("print start main");
    first();
    printf("print exit main\n");
    
    return 0;
}

I dont want add asm code, only C. I try to find the address of the rbp but I dont know how.

  • 3
    Why? What is the *actual* problem you need to solve? Or is this just curiosity (which is fine, but please [edit] your question to say so)? Right now this is too much of an [XY problem](https://xyproblem.info/). – Some programmer dude Oct 27 '22 at 11:21
  • 1
    By the way, what you want to do *is* possible, but not really recommended as it tend to make code harder to follow and understand and maintain. Depending on your actual problem, there might be other and perhaps better solutions. – Some programmer dude Oct 27 '22 at 11:23
  • 1
    BTW: there are no C "scripts". – Jabberwocky Oct 27 '22 at 11:24
  • 1
    You may want to look into [`setjmp/longjmp`](https://en.cppreference.com/w/c/program/longjmp) which allows similar some quirks like the one you're trying to achive. But even with that you cannot achieve this because with `longjmp` you can only jump to a place right after a `setjmp` that has already been executed. – Jabberwocky Oct 27 '22 at 11:30
  • To skip `printf("dont print this");` by adding stuff into `sec` you need to add assembly code in `sec` which is totally dependent on the compiler, the compiler version, compiler flags, the host platform and possibly a bunch of other things. IOW you cannot do this in standard C. You cannot find the content of `rbp` either just with C statements. BTW: rbp has no addresse because it's a register. – Jabberwocky Oct 27 '22 at 11:32
  • 1
    "I dont want add asm code, only C" Not possible.... Depending on compiler/compiler settings it may even be impossible in assembly – Support Ukraine Oct 27 '22 at 11:40
  • @Aconcagua As I wrote in the comment, you can't longjump to a setjmp that hasn't been executed previously. And try/catch is C++ and SEH/dwarf is not standard C. – Jabberwocky Oct 27 '22 at 11:48
  • 2
    It's incredibly bad practice to manually tweak the stack pointer in any C program. The only reason you would ever want or need to do that is if you are building your own RTOS or similar. Either way, in the program you described `sec` cannot return to where `first` was supposed to return, because you didn't save the return address anywhere. The executed machine code did - by accessing the stack in _assembler_ you could dig up the return address from there. But since you don't want asm code, there is no solution. Tough luck. – Lundin Oct 27 '22 at 11:50
  • What's your use case? Is it just out of curiosity just to explore what can be done (that's fine), or is this needed in some real world code (that's probably a bad idea)? – Jabberwocky Oct 27 '22 at 11:52
  • Joining @Jabberwocky – what do you try to achieve with? We might be talking about an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)! – Aconcagua Oct 27 '22 at 12:03
  • 1
    @Jabberwocky Since `setjmp` returns different values if used to set the jump-point, and when being used for a `longjmp` it can be used to before the call to `first()` and skip over the call if being used by a `longjmp`. – Some programmer dude Oct 27 '22 at 12:05
  • Are you maybe supposed to invoke undefined behavior to make `sec` return directly to `main`? If so, you need to examine the stack under debugger to find out offsets of return addresses, and overwrite `sec` return address witj `first` return address. Note that this will break horribly, if you change optimizations levels, which might for example inline both functions... – hyde Oct 27 '22 at 12:06
  • @Lundin It's certainly possible to modify return addresses with simple out of bounds `uintptr_t smasher[1];` access. It's probably even possible to make heuristic which will find the address offsets from stack by comparing to function addresses. Of course very UB at C level, but so would modifying the SP register with asm be. – hyde Oct 27 '22 at 12:14
  • @Aconcagua `/*change only here */` in `sec` seems quite unambiquous to me. – hyde Oct 27 '22 at 12:16
  • @hyde Oh. Lost that from focus. Agree... (Red herring was a comment in an answer citing only last phrase before first code segment – which isn't that explicit.) – Aconcagua Oct 27 '22 at 12:53

1 Answers1

0

Disclaimer: this code should not exist. It is non-portable, makes a lot of assumptions, and relies on a gaping UB. Nevertheless,

#include <execinfo.h>

void sec() 
{
    /*change only here */
    void * bt[4];
    int size = backtrace(bt, 4);

    while (bt[size] != bt[1])
        size++;
    bt[size++] = bt[2];

    while (bt[size] != bt[2])
        size++;
    bt[size] = bt[3];
    printf("print this from sec");
}

backtrace return an array of four pointers:

  • where backtrace should return,
  • where sec should return,
  • where first should return, and
  • where main should return.

The following two loops go up the stack looking for those addresses, and patches them to point to next frame.

Try to comment out the second loop, and observe that print exit main is printed twice. Do you see why?

user58697
  • 7,808
  • 1
  • 14
  • 28