c++visual-studio-2017self-modifying

Modifying region of memory - returns 0xCC VC++


I am modifying some sections of an executable code compiled in a dll. But a single byte at a fixed address from the entire segment that I am modifying can't be changed, not even read.

The code is very simple:

SEGMENT_DATA segInfo = getSegmentInfo(mHandle, segmentName);

if (segInfo.inFileSegmentAddr == 0) return false;

DWORD mOlProtection;
DWORD mOlProtection_1;

if (segInfo.architecture != MY_ARCH) {
    printf(" Not the same architecture!\n");
    return 0;
}

if(VirtualProtect((LPVOID)segInfo.segmentAddr, segInfo.segmentSize, PAGE_EXECUTE_READWRITE, &mOlProtection)==0) return false;
DWORD i=0;
for (size_t k = 0; k < segInfo.segmentSize; k++) {
    BYTE *lpByteValue = (BYTE*)(segInfo.segmentAddr + k);

    BYTE temp = *lpByteValue;
    *lpByteValue = temp ^ lDecryptionKey[i];
    i++;
    i %= decryptionKeyLength;
}

if(VirtualProtect((LPVOID)segInfo.segmentAddr, segInfo.segmentSize, mOlProtection, &mOlProtection_1)==0) return false;

Observations:

  1. Before I modify the memory, I "unprotect" the region with PAGE_EXECUTE_READWRITE flag.
  2. Memory View in visual studio clearly shows me the value at that particular address. Even weirder is that in the second I modify the value manually from the debugger, my code is also able to change that value.
  3. temp variable in the example code contains the value 0xCC
  4. This byte is literally the only one unchanged in a sea of hundred other bytes. It is the only byte marked black in Memory View (the rest are red because they were changed)
  5. Dll is compiled in Debug/x86 . /MTd flag set. No random address (/DYNAMICBASE : NO , /FIXED: NO). No Whole program optimization.
  6. The unmodified byte IS NOT a variable. So it can't be "uninitialized". It is actually a very important byte: it is the instruction opcode. Everything crashes on that byte.
  7. The decryption routine (XOR code) has no effect on the error. I step into the code and look at temp's value before it reaches the xor. This means the decryption key is never used and therefore it can't cause the problem.
  8. Virtual protect succeeds.


Snapshots: The black byte cannot be read or written to although visaul studio can display it


Visual studio can read the address Visual studio can read the address



Can't read byte inside program Can't read byte inside program


I know it's not the value of the byte at that single address that is causing problems (because I found other bytes with the same value that were processed successfully). Perhaps the byte is still "protected"?

Why is this happening?


Solution

  • You could very well deal with a very common scenario of Software Breakpoints. Software breakpoints are in fact set by replacing the instruction to be breakpointed with a breakpoint instruction.

    The breakpoint instruction is present in most CPUs, and usually as short as the shortest instruction, so only one byte on x86 (0xCC, INT 3).

    As I don't know if there are any breakpoints at all in your source I can only assume that this is your problem.