I have a value I receive in an unsigned byte array that I would like to dereference as a float. Take ptr as a uint8_t* pointing at a byte array of four values 0,0,0xCD,0x42 (this is a little endian system).
float val = *(float*)ptr;
is return -1.34e8
When I type:
*(float*)ptr;
In the expressions window after hitting a break point in that section of code, it gives me 102.5 as expected. Further, when I type:
*(float*)(ptr - 1);
I get the incorrect -1.34e8, as if the compiler used ptr - 1 instead of what I typed.
I'm confused - am I missing something here?
Basically the deref is correct.
If you printf("%p", ptr); do you get an address that is maybe not 4-byte aligned (or at least 2-byte aligned)? This may be necessary on some platforms.
For test, just pass the value of a real float in the uint8_t*, e.g.
float f= 102.5;
yourfunct((uint8_t*)&f);
and see if that works.
*(float*)(ptr - 1);
is the same as this
ptr--; //move the pointer to point to charackter in front of the previous one
*(float*)ptr;
Is this your intention ?
Or do you just want to subtract 1 from the value that is being pointed to be ptr.
Related
I am new to reversing. I have stumbled upon a line of code which I am unable to understand.
return (*(_int64(**)(void))(**(_QWORD **)(v1 + 0x3C8) + 0x68LL ))();
The code is for arm64 lib. So , what I understood is that it's returning a pointer out as unsigned int64 data type. But , when I try to use it as ,
return (unsigned long) ((unsigned long)(v1 + 0x3C8) + 0x68) ;
, the result is so out of the unsigned long range , for example one result is 19985131375820901. Also , _int64 and _QWORD both have the size of 8 bytes and so does unsigned long. So I am a little confused here how is this happening. Can anybody help with the correct interpretation of this pls ?
v1 + 0x3C8
Yes. This adds 0x3C8 to v1. But you seemed to have overlooked something else that happens before 0x68 gets added to it.
(_QWORD **)
The result of this addition gets casted to a pointer to a pointer to a _QWORD. That's what this means in C++.
**
And dereferenced. Twice. That produces a _QWORD, from somewhere. Wherever those pointers lead to.
+0x68LL
And only then does 0x68 gets added to whatever you have now.
But you're not done yet. There's still more C++ code left that you need to unravel.
(_int64(**)(void))
This gets now casted to a pointer to a pointer to a function that takes no parameters and returns an _int64.
*
And the pointer dereferenced.
()
And the function call is finally made, which returns an _int64 value.
I have a question about pointers, and memory addresses:
Supposing I have the following code:
int * array = (int *) malloc(sizeof(int) * 4);
Now in array im storing a memory address, I know that c++ takes already care when adding +1 to this pointer it will add 4 bytes, but what If I want to add manually 4 bytes?
array + 0x004
If im correct this will lead to add 4*4 (16) bytes, but my Idea is to add manually those 4 bytes.
Why? Just playing around, i've tried this and I got a totally different result from what I expected, then i've researched and i've seen that c++ takes already care when you add +1 to a pointer (it sums 4 bytes in this case).
Any idea?
For a pointer p to a type T with value v, the expression p+n will (on most systems anyway) result in a pointer to the address v+n*sizeof(T). To get a fixed-byte offset to the pointer, you can first cast it to a character pointer, like this:
reinterpret_cast<T*>(reinterpret_cast<char*>(p) + n)
In c++, sizeof(char) is defined to be equal to 1.
Do note that accessing improperly aligned values can have large performance penalties.
Another thing to note is that, in general, casting pointers to different types is not allowed (called the strict aliasing rule), but an exception is explicitly made for casting any pointer type to char* and back.
The trick is convert the type of array into any pointer-type with a size of 1 Byte, or store the pointer value in an integer.
#include <stdint.h>
int* increment_1(int* ptr) {
//C-Style
return (int*)(((char*)ptr) + 4);
}
int* increment_2(int* ptr) {
//C++-Style
char* result = reinterpret_cast<char*>(ptr);
result += 4;
return reinterpret_cast<int*>(result);
}
int* increment_3(int* ptr) {
//Store in integer
intptr_t result = reinterpret_cast<intptr_t>(ptr);
result += 4;
return reinterpret_cast<int*>(result);
}
Consider that if you add an arbitrary number of bytes to an address of an object of type T, it no longer makes sense to use a pointer of type T, since there might not be an object of type T at the incremented memory address.
If you want to access a particular byte of an object, you can do so using a pointer to a char, unsigned char or std::byte. Such objects are the size of a byte, so incrementing behaves just as you would like. Furthermore, while rules of C++ disallow accessing objects using incompatible pointers, these three types are excempt of that rule and are allowed to access objects of any type.
So, given
int * array = ....
You can access the byte at index 4 like this:
auto ptr = reinterpret_cast<unsigned char*>(array);
auto byte_at_index_4 = ptr + 4;
array + 0x004
If im correct this will lead to add 4*4 (16) bytes
Assuming sizeof(int) happens to be 4, then yes. But size of int is not guaranteed to be 4.
Can someone explain to me what's going on in this code block? Specifically on line 3. I have a hunch the * before ptr is significant. And (uint8_t *) looks like a cast to a byte... But what's up with the *? It also looks like r, g, and b will all evaluate to the same value.
case TRUECOLOR: { // 24-bit ('truecolor') image (no palette)
uint8_t pixelNum, r, g, b,
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS * 3];
for(pixelNum = 0; pixelNum < NUM_LEDS; pixelNum++) {
r = *ptr++;
g = *ptr++;
b = *ptr++;
strip.setPixelColor(pixelNum, r, g, b);
}
I work primarily in C#.
The second and third line can be expressed more cleanly:
uint8_t pixelNum;
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t *ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS * 3];
The first four variable declarations should be fairly simple, the fifth one is something C# does not have. It declares ptr as a pointer to a uint8_t. This pointer is set to the address of the value which is the imageLine * NUM_LEDS * 3th element in the imagePixels array. As this might be a different type (maybe a pointer to a char, who knows), this value is cast to a pointer to an uint8_t.
The next occurence of the asterisk (*) is in the for-loop body, where it is used as the dereference operator, which basically resolves a pointer to get the actual value.
Pointers 101
A pointer is like the street address of a house. It shows you where the house is so you can find it, but when you pass it around, you don't pass around the whole house. You can dereference it, meaning you can actually visit the house.
The two operators used in conjunction with pointers are the asterisk (*) and the ampersand (&). The asterisk is used in declarations of pointers and to dereference a pointer, the ampersand is used to get the address of something.
Take a look at the following example:
int x = 12;
int *y = &x;
std::cout << "X is " << *y; // Will print "X is 12"
We declare x as an int holding the value 12. Now we declare y as a pointer to an int, and set it to point at x by storing x's address. By using *y, we access the actual value of x, the int that y points at.
Since a pointer is a type of reference, modifying the value via the pointer changes the actual value of the thing pointed at.
int x = 12;
int *y = &x;
*y = 10;
std::cout << "X is " << x; // Will print "X is 10"
Pointers 102
Pointers are a large topic, and I suggest you take your time to read about them from different sources if necessary.
Used in a variable definition, the * means ptr is a pointer. The value it stores is an address in memory for another variable or a part of another variable. In this case ptr is a pointer to a block of memory inside imagePixels and from the names of the variables involved it's a line in an image. Since the type is uint8_t, this is taking whatever imagePixels is and using it as a block of individual bytes.
Used outside a varable definition, the * takes on a different meaning: dereference the pointer. Go to the location in memory stored in the pointer and get the value.
And yeah, * can also be used for multiplication, upping the code-reading fun level.
Incrementing (++) a pointer moves the address to the next address. If you had a uint32_t * the address would advance by 4 to point at the next uint32_t. In this case we have uint8_t, so the address is advanced one byte. So
r = *ptr++;
A) Get value at pointer.
After A) Advance the pointer.
After A) Assign value to r.
Exactly where the "advance the pointer" stage goes is tricky. It is after step A. In C++17 or greater it is before "Assign the value" because there is now a separation between the stuff on the right and the stuff on the left of an equals sign. But before C++17 all we can say is it's after step A. Search keyterm: "Sequence Points".
g = *ptr++;
b = *ptr++;
Do it again, get and assign the current value at ptr, advance the pointer.
strip.setPixelColor(pixelNum, r, g, b);
From the naming I presume this sets a given pixel to the colours read above.
You can't just
strip.setPixelColor(pixelNum, *ptr++, *ptr++, *ptr++);
Because of sequencing again. There are no guarantees of the order in which the parameters will be computed. This is to allow compiler developers to make optimizations for speed and size that they cannot if the ordering is specified, but it's a kick in the teeth to those expecting left-to-right resolution. My understanding is this still holds true in the C++17 standard.
OK. So what is this doing?
There is a big block of memory from which you want one and only one line.
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS * 3];
pinpoints the beginning of that line and sets it up to be treated like a dumb array of bytes.
for(pixelNum = 0; pixelNum < NUM_LEDS; pixelNum++) {
Generic for loop. For all the pixels on the line of LEDs.
r = *ptr++;
g = *ptr++;
b = *ptr++;
Get the colour of one pixel on the line in the standard 8 bit RGB format and point at the next pixel
strip.setPixelColor(pixelNum, r, g, b);
writes the read colour to one pixel.
The for loop will then loop around and start working on the next pixel until there are no more pixels on the line.
The asterisk(*) is the symbol for a pointer. So the (uint8_t *) is a cast to a pointer that is pointing to a uint8_t. Then within the loop, where the asterisk is prefixed to a symbol (ie *ptr) that is dereferencing that pointer. Dereferencing the pointer returns the data that the pointer is pointing to.
I suggest reading a bit about pointers as they are critical to understanding C/C++. Here is the C++ Docs on Pointers
MildlyInformed, I would need more code to run through it to explain it. One tool I found really, really useful though is the C visualizer. It's an online debug tool that helps you figure out what's happening in code by running you through step-by-step, line by line. It can be found at: http://www.pythontutor.com/visualize.html#mode=edit
Even though the URL talks about python, it can do C and a bunch of languages. I would have commented instead of posting an answer, but my rep isn't high enough. I hope this helps!
(I'm not affiliated with the above website, other than to use it occasionally when I'm baffled)
I am trying to perform arithmetic on an address. I need to make sure that it is on a 4 byte word boundary. This requires me to get an unsigned integer representation of the pointer to perform some math on. I have done this:
//memStartAddr is of type void* (from an external API function)
data32 tempAddr = reinterpret_cast<data32>(memStartAddr);
//adjust pointer to the next word boundary if needed
tempAddr = wordAlign(tempAddr);
//memStartAddress is a class variable of type unsigned char*
memStartAddress = reinterpret_cast<data8*>(tempAddr);
//calculate bytes lost due to above adjustment
data32 delta = (tempAddr - reinterpret_cast<data32>(memStartAddress));
//Take advantage of integer arithmetic to ensure usable size is a multiple
//of 4 bytes. Remainders are lost. Shrinks usable size if necessary.
memSize = ((size - delta) / 4) * 4;
This all works in my tests, however, using reinterpret_cast is considered a forbidden practice. Is there another way to do this? Or is an exception to the rule warranted here?
You're looking for memStartAddress = std::align(4, objSize, memStartAddr, objSize+3);. The standard function is a bit more flexible than you need, so you need to tell it that you want at most a +3 change in address.
a tricky approach might be to have pointer to initial address
then on the pointer perform + 1 --> this will automatically result in the next address according to the size in bytes of the variable type it's pointing to.
Note: make sure you perform the +1 on the pointer not on the address (int* initialAddress --> perform the operation on initialAddress not on *initialAddress)
then you can perform a subtraction between the two and you'll have the number of bytes.
I suggest you avoid division.
Try this:
unsigned int pointer_value = (unsigned int) pointer;
if ((pointer_value & 0x3U) == 0U)
{
// Pointer is on 4 byte boundary.
}
Some compilers may only optimize division by 4 and multiplication by 4 when the optimization levels are set on high. The embedded compiler I'm using will call the division function when dividing by 4 rather than right shifting, unless the optimization setting is cranked up to high.
Could be that I am overlooking something obvious, but where is pointer metadata stored? For instance if I have a 32-bit int pointer ptr and I execute ptr++ it knows to advance 4 bytes in memory. However, if I have a 64-bit int pointer it knows to advance 8 bytes. So who keeps track of what type of pointer ptr is and where is it stored? For simplicity you can limit this to C++.
It isn't stored anywhere, per-se. The compiler looks at the type of the ptr and turns the ++ operation into an increment of the correct number of bytes.
In the symbol table while the compiler runs. Nowhere while your program runs, or rather it is implicit in the lower level code produced by the compiler.
It's not stored anywhere, it's determined at compile time. In fact, take this code as an example:
int *abc = NULL;
cout << abc + 1; /* Prints sizeof(int) */
cout << (void *)((char *)abc + 1); /* Prints 1. Casting it back to void * is necessary,
otherwise it will try to dereference it and print as a string. */