1

So I am working on trying to execute a function from main in c without explicitly calling it by manipulating the stack on a 32 bit ARM architecture machine. My c code is as follows:

    #include <stdio.h>
    #include <stdlib.h>
    void function2(){
        printf("You have hit the target! :)\n");
        exit(0);
    }

    void main(int argc, char**argv){
        int i;
        for(i = 0; i < 20; i++){
            printf("ADDR: 0x%x -> 0x%x\n", (int*)(&argc+i), *(int*)(&argc+i));
        }
    }  

From my understanding and from what was printed when I disassembled my main function using gdb, the link register is pushed onto the stack along with the frame pointer. Understand that the sole purpose of the loop above was to iterate through the stack to obtain the address of the link register on the stack.Then, I was going to edit my c code to change the value on the stack at that address to the first address of function2(). The output on my machine is as follows:

    ADDR: 0x7eb9424c -> 0x1
    ADDR: 0x7eb94250 -> 0x0
    ADDR: 0x7eb94254 -> 0x2
    ADDR: 0x7eb94258 -> 0x0
    ADDR: 0x7eb9425c -> 0x76d82294
    ADDR: 0x7eb94260 -> 0x76ea7000
    ADDR: 0x7eb94264 -> 0x7eb943b4
    ADDR: 0x7eb94268 -> 0x1
    ADDR: 0x7eb9426c -> 0x10498
    ADDR: 0x7eb94270 -> 0x76eff318
    ADDR: 0x7eb94274 -> 0x76eff000
    ADDR: 0x7eb94278 -> 0x0
    ADDR: 0x7eb9427c -> 0x0
    ADDR: 0x7eb94280 -> 0x10354
    ADDR: 0x7eb94284 -> 0x0
    ADDR: 0x7eb94288 -> 0x0
    ADDR: 0x7eb9428c -> 0x0
    ADDR: 0x7eb94290 -> 0x76f03000
    ADDR: 0x7eb94294 -> 0x0
    ADDR: 0x7eb94298 -> 0x6a7a8fc7 

But when I gdb my program and get the info of the registers:

0             0x1   1
r1             0x7efff384   2130703236
r2             0x7efff38c   2130703244
r3             0x10498  66712
r4             0x0  0
r5             0x0  0
r6             0x10354  66388
r7             0x0  0
r8             0x0  0
r9             0x0  0
r10            0x76fff000   1996484608
r11            0x7efff22c   2130702892
r12            0x76fa3000   1996107776
sp             0x7efff218   0x7efff218
lr             0x76e7e294   1994908308
pc             0x104ac  0x104ac <main+20>
cpsr           0x60000010   1610612752

So the LR (link register) has a value of 0x76e7e294, but none of the dereferenced memory addresses on the stack yielded this value. Am I doing something wrong? Or is there some edge case where I am unable to access the stack frame of main?

EDIT: For anyone reading this, if you type in the gdb command 'info frame', you will print the stack frame of the function you are currently "within".

Koiix
  • 66
  • 7
  • Maybe in the ARM world, this is a stupid question, but, why do you expect the stack to contain a copy of the current LR? – jwdonahue Nov 28 '17 at 03:54
  • @jwdonahue Sorry; I perhaps should have included the disassembled c code, but it indicated that both the frame pointer and the link register value are pushed onto the stack of main, whether it is a leaf function (calls another function), or not. I guess I just assumed this would be the case for every call to main. – Koiix Nov 28 '17 at 03:58
  • I don't recall the ABI details for ARM, but I am pretty sure that your args are the last things pushed to the stack. I think you may be looking in the wrong direction. Anyway, you normally shouldn't be poking around in your stack like that. Why can't you simply call the function? Experimenting with exploits? – jwdonahue Nov 28 '17 at 04:05
  • @jwdonahue so if the args are the last things pushed to the stack and the stack grows down, shouldn’t I iterate to higher addresses to find the things pushed onto the stack beforehand? I’m experimenting, yes :) – Koiix Nov 28 '17 at 04:28
  • @Loiix, seems a reasonable assumption if the stack actually grows down on that architecture. Your other assumption is that the current value of lr is the value that was pushed to the stack. Perhaps it is some other value that was pushed earlier? – jwdonahue Nov 28 '17 at 04:35
  • @Loiix, why don't you start with argv instead of argc, you should be able to predict where in the stack argc will be relative to argv, based on the number of arguments passed to the program. Find that argc and I think you've confirmed the correct direction. Oh, one other assumption you should verify is what is the word size of elements on the stack and is sizeof(int) equal to that? – jwdonahue Nov 28 '17 at 04:40
  • @jwdonahue Ok. I have confirmed my assumption about the direction, and I am very certain of the word size of the elements on the stack because ARM has fixed memory address size of 32 bits (4 bytes). So all that is left of the unresolved assumptions is that a value other than the current value of the LR was pushed to the stack, which I am unsure of how to prove. – Koiix Nov 28 '17 at 05:04
  • 1
    As per [ARM Link register and frame pointer](https://stackoverflow.com/questions/15752188/arm-link-register-and-frame-pointer/15752671#15752671), `LR` will not be emitted for a leaf function. Your `function2()` must be global and not inlined (ie, complex) and call another global function for the compiler to save an `LR` with most optimization levels. With *LTO*, it may still not save `LR`. What you are trying to do is very 'brittle' and can easily fail with small modifications of code/compiler or options. – artless noise Nov 28 '17 at 15:56
  • @artlessnoise, that sounds like the answer to me. – jwdonahue Nov 28 '17 at 22:27
  • @artlessnoise I understand the "brittleness" of the task, but from the disassembled code for main, it shows that it pushes both the `LR` and the frame pointer onto the stack. Do you know if it is possible that the value in my `LR` register could be changed after I push it on the stack, even if the code doesn't specify the change? (like how the `pc` is changed by default without showing the exact iteration of it in the code) – Koiix Nov 28 '17 at 23:56
  • 1
    The `LR` that main pushes on the stack is the **CALLER** of main. It is usually `_start`. The `LR` (physical register) is where to return to main. You won't find *0x76e7e294* on the stack (gdb 'lr' value). If `LR` (or 0x76e7e294 is `_start`), then your Frame pointer stored `LR` will be zero to terminate stack traces. – artless noise Nov 29 '17 at 14:57
  • @artlessnoise Thanks for the insight. I figured out that the value in my `LR` is changed without the assembly telling me. – Koiix Nov 30 '17 at 06:47

0 Answers0