Dereferencing a casted void pointer and using post increment operator - c

I have a function
foo(void *buf) {
int i = 0;
unsigned char ptr = get_user_name();
//I want the buffer to hold user name from some position onwards
for(i=0;i<MESSAGE_LTH;i++)
*( (unsigned char*)(buf) + sizeof(some_struct)) ++ = ptr[i];
}
I am getting error: lvalue required as increment operand
I want the buffer to hold the username soon after the struct;

This:
unsigned char ptr = get_user_name();
seems like it should be:
const unsigned char *ptr = get_user_name();
It must be a pointer since you're accessing it like one. It should be const since you're only reading from it.
The copying should be done using memcpy(), and incrementing the pointer afterwards can be done separately:
unsigned char *put = buf; /* Proper type, for pointer arithmetic. */
put += sizeof(some_struct); /* Advance into the buffer. */
memcpy(put, ptr, MESSAGE_LTH); /* Do the copy. */
put += MESSAGE_LTH; /* Advance the pointer to after the name. */
Of course at the end of the above, it's hard to know what to do with put. Perhaps returning it out of the function would make sense, but you don't specify.

That line should be rewritten as
*( (unsigned char*)(buf) + sizeof(some_struct) + i) = ptr[i];
Indeed, an easier-to-understand implementation:
memcpy(buf + sizeof(some_struct), ptr, MESSAGE_LTH);
without the loop.

Related

Confusing C syntax

I encountered some code in a tutorial about buffer overflows.
It's a program that exploits a simple program that is vulnerable to a buffer overflow (if some stack protection mechanisms are turned off).
My question is: what is the for loop doing? I mean the line within the for loop:
*(void **)(buf + i) = addr;
Its a bit of a strange syntax that I haven't seen before, or maybe I have seen it but it just confuses me.
The idea of the program is that the buf is passed as argument to the vulnerable program and through a strcpy it will overwrite the return address on the stack such that it will run the shellcode that is passed in an environment parameter.
Thanks!
The full code:
int main(int argc, char **argv) {
void *addr = (char *) 0xc0000000 - 4 - (strlen(VULN) + 1) - (strlen(&shellcode) + 1);
char buf[768];
size_t i;
for (i = 0; i < sizeof(buf); i += sizeof(void *)) {
*(void **)(buf + i) = addr;
}
char *params[] = { VULN, buf, NULL };
char *env[] = { &shellcode, NULL };
execve(VULN, params, env);
perror("execve");
return -1;
}
C has a kind of Treehorn type system. For any object x of type T, you can pretend it's an object of a different type. To do so, you cast the address of the object. So, in steps:
T x; is an object of type T.
&x is the address of the object, it's of type T * – "pointer to T".
Now pretend this is a pointer to something else: (U *)(&x) – a "pointer to U", but it's the same value.
If we dereference that, we treat the object x as though it were a U: *(U *)(&x)
Now apply all this to T = char, x = buf[i] and U = void * in your code. Note that &buf[i] is identical to buf + i. Also note that i is incremented in strides of sizeof(void *) so that each round of the loop doesn't step on the memory touched by the previous rounds.
A word of warning: it is generally not allowed to treat one object as though it were one of a different type; this is undefined behavior. There are only some exceptions; e.g. you can treat an int as though it were an unsigned int, and you can treat any object x as though it were a char[sizeof x]. (None of these are the case in your code, which is not well-formed.)
First, it calculates a value which will remain constant throughout the execution of the for loop:
0xc0000000 - 4 - (strlen(VULN) + 1) - (strlen(&shellcode) + 1)
Then, inside the for loop, it writes this constant value into every "4-byte entry" in the buf array:
buf[0...3] = the constant value
buf[4...7] = the constant value
buf[8...11] = the constant value
...
buf[764...767] = the constant value

What's the right way to reinterpret memory in C?

I've lost count, long ago, of the number of times I've done something like this in C:
struct foo f;
struct foo* pf = &f;
char* pc = (char*) pf;
transmit(pc, sizeof(f));
Or perhaps:
char* buffer[1024];
receive(buffer, 1024);
float values[256];
for(int ii = 0; ii < 256; ii++) {
float* pf = (float*)(buffer + ii*4);
values[ii] = *pf;
}
Or maybe:
uint32_t ipAddress = ...;
uint8_t* p = (uint8_t*)&ipAddress;
uint8_t octets[4] = {p[0], p[1], p[2], p[3]};
printf("%d.%d.%d.%d\n", octets[0], octets[1], octets[2], octets[3]);
I've only just discovered that reinterpreting a piece of memory like this by casting to another pointer type invokes undefined behaviour. And yet all of the the above examples are meant to do are absolutely necessary. What's the right way of doing them?
Casting to char * (or unsigned char * or typedefs thereof) is a special case, and does not cause undefined behaviour.
From the C spec, 6.3.2.3 Pointers, paragraph 7:
When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
Your first & third examples are covered by this case. The second example is a bit hinky, but will probably work on most systems. What you really should be doing is either reading directly into values:
float values[256];
receive(values, sizeof values); // assuming receive() takes a "void *" parameter
Or something like this (to avoid alignment problems):
char buffer[1024];
receive(buffer, sizeof buffer);
float values[256];
for(int i = 0; i < 256; i++)
{
char *pf = (char *)&values[i];
memcpy(pf, buffer + i * sizeof(float), sizeof(float));
}
(Note I changed buffer to be a char array - I assume that was a typo in your question).

C casting from uint32_t* to void *

I have a question about pointer casting for C.
if I have a function with this signature:
uint8_t input_getc(void)
which reads user input from STDIN.
Then I have a pointer
void* buffer
that I store return values from input_getc() in. What would be the proper way to cast this?
//read user input
for(i = 0; i < SIZE; ++i)
{
uint8_t temp = input_getc();
//copy to void* buffer
*(uint8_t *)(buffer + i) = temp //WAY #1
*(buffer + i) = (void *)temp; //WAY #2
}
Are both of these the same?
Thanks
As it is right now, neither of those methods will compile. Since buffer is a void* you can't do arithmetic on it since it has an unknown size.
It's not entirely clear exactly where you are trying to store it. If you're just trying to store the uint8_t into the memory location pointed by buffer with offset i, then it can be done like this:
((uint8_t*)buffer)[i] = temp;
EDIT :
Okay, apparently arithmetic on void* is allowed in C, but not in C++. However, doing so it still considered unsafe behavior.
See this question: Pointer arithmetic for void pointer in C
One way to do this is:
*(((uint8_t*)buffer)+i) = temp;
i am not understanding what do you mean by
copying to `void* buffer`
but if you are doing following thing then way1 is right
int main()
{
int i;
char a[10];
void *buffer;
buffer = &a; // buffer is void* type pointer and its pointing to some buffer then
for(i = 0; i < 10; ++i)
{
uint8_t temp = 65;
//copy to void* buffer
*(uint8_t *)(buffer + i) = temp; //WAY #1
}
printf("\n %s",a);
}
BIG Edit :
IN WAY1
you are adding +i offcet with void * buffer and still whole result is void* then you are typecasting that whole result with uint8_t* then accesing that value so it works
but in way2 you are adding +i offcet with void * buffer still whole result is void* and then you are accesing that value ...which is completely wrong..
you will get warning/error here
warning: dereferencing ‘void *’ pointer
One more Edit :
you can not dereferencing void* pointer but you can do arrithmetic operation with pointer value (not its pointe value)

What is the correct way to offset a pointer?

I want to pass a pointer to a function. I want this pointer to point to some place in the middle of an array. Say I have an array like such unsigned char BufferData[5000];, would the following statement be correct syntactically?
writeSECTOR( destAddress, (char *)( BufferData + (int)(i * 512 )) );
// destAddress is of type unsigned long
// writeSECTOR prototype: int writeSECTOR ( unsigned long a, char * p );
// i is an int
That would do, but just make it:
writeSECTOR( destAddress, &BufferData[i * 512]);
(It sounds like writeSECTOR really should take an unsigned char* though)
Pointer arithmetic is fairly simple to understand. If you have a pointer to the first element of an array then p + 1 points to the second element and so on regardless of size of each element. So even if you had an array of ints, or an arbitrary structure MyData it would hold true.
MyData data[100];
MyData *p1 = data;; // same as &data[0]
MyData *p2 = p1 + 1; // same as &data[1]
MyData *p3 = p2 + 1; // same as &data[2]
MyData *p4 = p2 - 1; // same as &data[0] again
If your array is unsigned char then you just add however many bytes offset you wish to go into the array, e.g.
unsigned char data[16384];
unsigned char *offset = data + 512; // same as &data[512]
*offset = 5; // same as data[512] = 5;
Alternatively if the notation is confusing, you can always refer to it as it is shown in comments above, e.g. &data[512]
You can just do BufferData + i * 512. An arithmetic + operator on char* yields a char* when you add an integer value to it.
That should work. In C, adding an integer to a pointer increases the pointer by the integer multiplied by the sizeof the type the pointer points to.
it looks ok, but try it on the compiler,
You can use writeSECTOR( destAddress, &BufferData[i * 512] );
That looks like it will pass in the address of the i*512'th element of the array. Is that what you want it to do?
I don't really see what that cast to int is buying you though.
That should work as you think.
Pointer in C is just an address in RAM,so you could drift the pointer in your measure.

How can I get/set a struct member by offset

Ignoring padding/alignment issues and given the following struct, what is best way to get and set the value of member_b without using the member name.
struct mystruct {
int member_a;
int member_b;
}
struct mystruct *s = malloc(sizeof(struct mystruct));
Put another way; How would you express the following in terms of pointers/offsets:
s->member_b = 3;
printf("%i",s->member_b);
My guess is to
calculate the offset by finding the sizeof the member_a (int)
cast the struct to a single word pointer type (char?)
create an int pointer and set the address (to *charpointer + offset?)
use my int pointer to set the memory contents
but I get a bit confused about casting to a char type or if something like memset is more apropriate or if generally i'm aproching this totally wrong.
Cheers for any help
The approach you've outlined is roughly correct, although you should use offsetof instead of attempting to figure out the offset on your own. I'm not sure why you mention memset -- it sets the contents of a block to a specified value, which seems quite unrelated to the question at hand.
Here's some code to demonstrate how it works:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
typedef struct x {
int member_a;
int member_b;
} x;
int main() {
x *s = malloc(sizeof(x));
char *base;
size_t offset;
int *b;
// initialize both members to known values
s->member_a = 1;
s->member_b = 2;
// get base address
base = (char *)s;
// and the offset to member_b
offset = offsetof(x, member_b);
// Compute address of member_b
b = (int *)(base+offset);
// write to member_b via our pointer
*b = 10;
// print out via name, to show it was changed to new value.
printf("%d\n", s->member_b);
return 0;
}
The full technique:
Get the offset using offsetof:
b_offset = offsetof(struct mystruct, member_b);
Get the address of your structure as a char * pointer.
char *sc = (char *)s;
Add the add the offset to the structure address, cast the value to a pointer to the appropriate type and dereference:
*(int *)(sc + b_offset)
Ignoring padding and alignment, as you said...
If the elements you're pointing to are entirely of a single type, as in your example, you can just cast the structure to the desired type and treat it as an array:
printf("%i", ((int *)(&s))[1]);
It's possible calculate the offset based on the struct and NULL as reference pointer
e.g " &(((type *)0)->field)"
Example:
struct my_struct {
int x;
int y;
int *m;
int *h;
};
int main()
{
printf("offset %d\n", (int) &((((struct my_struct*)0)->h)));
return 0;
}
In this particular example, you can address it by *((int *) ((char *) s + sizeof(int))). I'm not sure why you want that, so I'm assuming didactic purposes, therefore the explanation follows.
The bit of code translates as: take the memory starting at address s and treat it as memory pointing to char. To that address, add sizeof(int) char-chunks - you will get a new address. Take the value that the address thus created and treat it as an int.
Note that writing *(s + sizeof(int)) would give the address at s plus sizeof(int) sizeof(mystruct) chunks
Edit: as per Andrey's comment, using offsetof:
*((int *) ((byte *) s + offsetof(struct mystruct, member_b)))
Edit 2: I replaced all bytes with chars as sizeof(char) is guaranteed to be 1.
It sounds from your comments that what you're really doing is packing and unpacking a bunch of disparate data types into a single block of memory. While you can get away with doing that with direct pointer casts, as most of the other answers have suggested:
void set_int(void *block, size_t offset, int val)
{
char *p = block;
*(int *)(p + offset) = val;
}
int get_int(void *block, size_t offset)
{
char *p = block;
return *(int *)(p + offset);
}
The problem is that this is non-portable. There's no general way to ensure that the types are stored within your block with the correct alignment, and some architectures simply cannot do loads or stores to unaligned addresses. In the special case where the layout of your block is defined by a declared structure, it will be OK, because the struct layout will include the necessary padding to ensure the right alignment. However since you can't access the members by name, it sounds like this isn't actually what you're doing.
To do this portably, you need to use memcpy:
void set_int(void *block, size_t offset, int val)
{
char *p = block;
memcpy(p + offset, &val, sizeof val);
}
int get_int(void *block, size_t offset)
{
char *p = block;
int val;
memcpy(&val, p + offset, sizeof val);
return val;
}
(similar for the other types).

Resources