A little theory
Just triedIf you want to see actual trick to write at custom address jump to second part.
Lets try tweaking format string intoin printf() trick.
Breakpoint 1, __printf (format=0x555555556004 "ABABABAB") at ./stdio-common/printf.c:28
As you can see that format string address indeed resides in .rodata section of process:
(gdb) i args
format = 0x555555556004 "ABABABAB"
So how is address of format string passed to prIntf()? When When we dumped registers we saw format string address in rsi register.
Because function arguments (string address in this case) will be passed in rsi and rdi registers for purpose of speed and not in the stack we cant use format string and string arguments for this trick.
So youwe can just use strings created as local (automatic) variables to be put in stack, before return address in current stack frame, because function arguments (string address in this case) will be passed in rsi and rdi registers for purpose of speed.
Actual example
Anyway I tried this small example and it worked, printed out addresses put in local strings (created on stack). SOSo we could use this trick to make local strings mimic addresses we want to access:
Using hexadecimal format %x showed HEX representation of strings avro, nana, loli on stack (using %s string format would cause segmentation fault because printf() would interpret those values as addresses of strings but those "addresses" are probably not in mapped area of the process or are in protected memory area):
So now we used local variables on stack to "masquerade" as data access. But what if we can use this to try to write on that address?
Lets change last %X format specifier to %n. Instead of printing content of data on stack with %X, we will use this data as address of variable where printf() stores number of characters already printed. So idea is to gain write access to custom address.
printf("ABABABAB\n,%016llX\n,%016llX\n,%016llX\n,%016llX\n,%016llX\n,%016llX\n,%016llX\n,%n");
Our FAKE address 0x61616161616161 represented as ASCII "aaaaaaa" ends in %rax register, and printf will write at this address number of characters already printed (stored in r12):
(gdb) i r
rax 0x61616161616161 27410143614427489
rbx 0x555555556052 93824992239698
0x00007ffff7df7c3c <+7180>: jne 0x7ffff7df8276 <__vfprintf_internal+8774>
=> 0x00007ffff7df7c42 <+7186>: mov %r12d,(%rax)
But in our case this will use SEGV segmentation fault since address 0x61616161616161 is not mapped into process memory.
Continuing.
ABABABAB
,00007FFFFFFFDF08
,00007FFFFFFFDF18
,0000555555557DB8
,00007FFFF7F9BF10
,00007FFFF7FC9040
,0031313131313131
,0032323232323232
Program received signal SIGSEGV, Segmentation fault.
I hope this helps!


