The code has undefined behavior and is invalid.
Anyway, the statement:
printf ("%16u%n", 7350, (int *) &foo[0]);
is basically doing:
*(int *)&foo[0] = 16;
The biggest issue is with the last one:
printf("%128u%n", 7350, (int *) &foo[3]);
it's doing:
*(int *)&foo[3] = 128;
but foo[3] is an unsigned char. Assuming sizeof(int) = 4, ie. int has 4 bytes, then this writes 3 bytes out of bounds to foo + 3. x86 stores stack in reverse order - the memory reserved for canary is put after the memory for foo. The stack memory looks like this:
<-- foo ---><--- canary ----->
[0][1][2][3][0][1][2][3][4][5]
^^^^^^^^^^^^
storing (int)128 here in **little endian**
Because x86 is little endian, foo[3] is assigned the value of 128, and canary[0..2] are zeroed (because 128 = 0x00000080).
You can do:
// I want it to print 0xDEAD
// I swap bytes for endianess I get 0xADDE
// I then shift it left by 8 bytes and get 0xADDE00
// 0xADDE00 = 11394560
// The following printf will do foo[3] = 0x00
// but also: canary[0] = 0xDE, canary[1] = 0xAD and canary[2] = 0x00
fprintf("%11394560u%n", 7350, (int *) &foo[3]);
printf("0x%02x%02x\n", canary[0], canary[1]);
// will output 0xDEAD
Answer from KamilCuk on Stack OverflowThe code has undefined behavior and is invalid.
Anyway, the statement:
printf ("%16u%n", 7350, (int *) &foo[0]);
is basically doing:
*(int *)&foo[0] = 16;
The biggest issue is with the last one:
printf("%128u%n", 7350, (int *) &foo[3]);
it's doing:
*(int *)&foo[3] = 128;
but foo[3] is an unsigned char. Assuming sizeof(int) = 4, ie. int has 4 bytes, then this writes 3 bytes out of bounds to foo + 3. x86 stores stack in reverse order - the memory reserved for canary is put after the memory for foo. The stack memory looks like this:
<-- foo ---><--- canary ----->
[0][1][2][3][0][1][2][3][4][5]
^^^^^^^^^^^^
storing (int)128 here in **little endian**
Because x86 is little endian, foo[3] is assigned the value of 128, and canary[0..2] are zeroed (because 128 = 0x00000080).
You can do:
// I want it to print 0xDEAD
// I swap bytes for endianess I get 0xADDE
// I then shift it left by 8 bytes and get 0xADDE00
// 0xADDE00 = 11394560
// The following printf will do foo[3] = 0x00
// but also: canary[0] = 0xDE, canary[1] = 0xAD and canary[2] = 0x00
fprintf("%11394560u%n", 7350, (int *) &foo[3]);
printf("0x%02x%02x\n", canary[0], canary[1]);
// will output 0xDEAD
why does it overwrite to the adjacent memory?
Undefined behavior (UB).
All lines below exhibit UB. What OP sees to a potential result, but not specified by C.
/* 0 * before */ strcpy (canary, "AAAA"); // Writing out of bounds
/* 1 */ printf ("%16u%n", 7350, (int *) &foo[0]); // Writing out of bounds, alignment issues.
/* 2 */ printf ("%32u%n", 7350, (int *) &foo[1]);
/* 3 */ printf ("%64u%n", 7350, (int *) &foo[2]);
/* 4 */ printf ("%128u%n", 7350, (int *) &foo[3]);
Videos
printf cannot write anywhere without using the %n format specifier. This is the one you're missing. Something like %.987654d%n will write the number 987654 (the number of characters output so far) to an address specified by the second argument, where the first argument is an int. This should be enough to get you started.
you should specify wich offset of the stack to write in with the %n formatter like %[offset]\$n
example : %23\$n
be sure to correctly get the right address by cheking the result of \xdd\xcc\xbb\xaa_%54321x_%[offset]\$x" this can be done with python or bash script
you should retrieve the address aabbccdd