If you fimilar with gdb and can control rip, then you are one step away from the solution.
Let's make a small example
void main() {
char* buff = "asdf";
}
void main() {
char* buff = "asdf";
}
compile it
$ gcc test.c
$ gcc test.c
and then use debugger
$ gdb a.out
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x00000000004004d6 <+0>: push rbp
0x00000000004004d7 <+1>: mov rbp,rsp
0x00000000004004da <+4>: mov QWORD PTR [rbp-0x8],0x400574
0x00000000004004e2 <+12>: nop
0x00000000004004e3 <+13>: pop rbp
0x00000000004004e4 <+14>: ret
End of assembler dump.
$ gdb a.out
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x00000000004004d6 <+0>: push rbp
0x00000000004004d7 <+1>: mov rbp,rsp
0x00000000004004da <+4>: mov QWORD PTR [rbp-0x8],0x400574
0x00000000004004e2 <+12>: nop
0x00000000004004e3 <+13>: pop rbp
0x00000000004004e4 <+14>: ret
End of assembler dump.
So our variable buff is at rbp-0x8 on the stack. If ASLR disabled - the address is always the same. You can get it with:
(gdb) break *0x00000000004004e2
Breakpoint 1 at 0x4004e2
(gdb) r
Starting program: ./a.out
Breakpoint 1, 0x00000000004004e2 in main ()
(gdb) p $rbp-0x8
$1 = (void *) 0x7fffffffdbd8
(gdb) break *0x00000000004004e2
Breakpoint 1 at 0x4004e2
(gdb) r
Starting program: ./a.out
Breakpoint 1, 0x00000000004004e2 in main ()
(gdb) p $rbp-0x8
$1 = (void *) 0x7fffffffdbd8