4

I have a int64 variable with a random value. I want to modify the lower 32 bits of it to 0xf0ffffff

The variable is rdx register but i want to edit edx value

ContextRecord->Rdx = 0xf0ffffff; // Not correct 
4

5 Answers 5

2

The variable is rdx register but i want to edit edx value

I assume that this means that you want to keep the most significant 32-bits intact and only change the least significant 32-bits.

Assuming that the data member ContextRecord->Rdx contains the original value and you want to write back the edited value to this data member, then you could use the following code:

auto temp = ContextRecord->Rdx; temp &= 0xffffffff00000000; //set least significant 32-bits to 00000000 temp |= 0x00000000f0ffffff; //set least significant 32-bits to f0ffffff ContextRecord->Rdx = temp; 

Of course, these lines could be combined into a single line, like this:

ContextRecord->Rdx = ContextRecord->Rdx & 0xffffffff00000000 | 0x00000000f0ffffff;

Please note that this line only works because & has a higher operator precedence than |, otherwise additional parentheses would be required.

Sign up to request clarification or add additional context in comments.

Comments

2

Read the whole value, mask out the lower bits and bitwise-OR it with the 32 bit value you want there:

#include <stdint.h> void f(int64_t *X) { *X = (*X & ~(uint64_t)0xffffffff) //mask out the lower 32 bits | 0xf0ffffff; //<value to set into the lower 32 bits } 

gcc and clang on little-endian architectures optimize it to a direct mov into the lower 32 bits, i.e., the equivalent of:

#include <string.h> //only works on little-endian architectures void g(int64_t *X) { uint32_t y = 0xf0ffffff; memcpy(X,&y,sizeof(y)); } 

https://gcc.godbolt.org/z/nkMSvw

Comments

2

If you were doing this in straight assembly, you could just

mov edx 0xf0ffffff 

as edx is an alias to the lower 32 bits of rdx. Since it seems you want to do it in C/C++, you need to adjust Rdx directly. Something like -

CONTEXT ctx; GetThreadContext(hYourThread,&ctx); // check return value, handle errors DWORD64 newRdx = ctx->Rdx; newRdx &= 0xfffffffff0ffffff; newRdx |= 0xf0ffffff; 

Comments

1

Need to write some unit tests as I haven't tested this for all types in all architectures but a template something like below maybe what you are looking for

#include <cassert> #include <cstdint> #include <iostream> #include <limits> #include <type_traits> template <const int bits, class /* This is where I wish concepts were completed */ T> constexpr T modifyBits(T highPart, T lowPart) { // std::numeric_limits<T>::max() will fail on bits == 0 or float types static_assert(bits != 0); static_assert(std::is_signed<T>::value || std::is_unsigned<T>::value); constexpr T almostallSetMask = std::numeric_limits<T>::max(); constexpr T bitmaskRaw = almostallSetMask >> (bits - (std::is_signed<T>::value ? 1 : 0)); constexpr T bitmaskHigh = bitmaskRaw << bits; constexpr T bitmaskLow = ~bitmaskHigh; return (highPart & bitmaskHigh) | (lowPart & bitmaskLow); } int main() { // Example usage constexpr int64_t value = 0xFFFFFFFF00000000LL; constexpr int64_t updated = modifyBits<32, int64_t>(value, 0xFFFFFFFFLL); static_assert(updated == -1LL); // has to pass return 0; } 

As you can see I can use static assert and const_expr in a generic way like this. The motto is: Write it once use everywhere. Be warned though, without unit tests this is not complete at all. Feel free to copy this if you like, you can consider it as CC0 or public domain,

1 Comment

Thanks but i'm in kernel mode
0

A slightly more cheaty and less recommendable way to do it would be type punning:

struct splitBytes { __int32 lower, upper; } void changeLower(__int64* num) { splitBytes* pun = (splitBytes*)*num; pun->lower = 0xf0ffffff; } 

note: type punning is pretty risky, so you really shouldn't use unless it's unavoidable. It basically lets you treat a block of memory as if it were of a different type. Really, don't use it if you can avoid it. I'm just putting it out there.

4 Comments

If I am not mistaken, the posted code violates the strict aliasing rule, which can at least theoretically cause undefined behavior.
@AndreasWenzel short answer: yup. long answer: it depends (you weren't expecting that, right?). basically, problems can arise if either: the punned type and the punning type have different sizes; at least one of the punned types is a class; arithmetic is done with the pointers. this is why it should almost never be done.
What you say may currently be true. However, compiler optimizations are becoming more and more aggressive. Whenever the compiler encounters code which causes undefined behavior, it can treat that code as unreachable, which means the compiler can simply optimize it away. See this very interesting answer by Microsoft Blogger Raymond Chen for more information on that topic.
@AndreasWenzel oh, I was completely unaware of that. The answer is informative and all round well worth reading. thanks!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.