3

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?

sergiu reznicencu
  • 1,039
  • 1
  • 11
  • 31
  • 1
    Does your decryption key contain a few zero bytes in it? – Ben Voigt Apr 25 '19 at 23:54
  • Could you provide more context, along with a short code we can compile and use to test this? – Alecto Irene Perez Apr 25 '19 at 23:55
  • No the key doesn't contain zeros. And regarding the compiling : I can't provide any aditional code. But I want to know only this: that there's no hidden "feature" of virtualprotect or another obvious memory-behaviour that would generate this error. If the code I provided wouldn't normally generate this error , at least you have provided me with a clue: that the error is somewhere else, burried in my code. – sergiu reznicencu Apr 26 '19 at 00:26
  • In what circumstances would by the way visual studio return 0xCC ? I found something related to unitializd memory. Could this be? – sergiu reznicencu Apr 26 '19 at 00:29
  • Added more details – sergiu reznicencu Apr 26 '19 at 00:34
  • The problem really is not from the decryption code. The temp variable is the point of interest. It holds 0xCC. It's a simple memory read. No code should interfere with that – sergiu reznicencu Apr 26 '19 at 00:35
  • I will not be able to respond until tomorrow. – sergiu reznicencu Apr 26 '19 at 00:39
  • 2
    0xCC means uninitialized memory. [When and why will an OS initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete?](https://stackoverflow.com/q/370195/995714) – phuclv Apr 26 '19 at 04:36
  • But how can it be uninitialized? After a few lines of code that section of memory that I am modifying will be executed. And besides I can clearly see the value in Memory View – sergiu reznicencu Apr 26 '19 at 07:33
  • The only thing that comes to mind is that your key either contains a null byte, or is shorter than you think: the absence of check or relation between `i` and `segInfo.segmentSize` looks fishy. – Quentin Apr 26 '19 at 08:55
  • The key does nothing. I step into the code and when `lpByteValue` reaches the address of that weird byte I look at `temp`'s value. I don't event execute that XOR. `temp`'s value is 0xCC. It has nothing to do with the decryption code. I could as well remove all of that code. And the code I provided is modified. That `i` is properly checked in the original code. I will edit the question. – sergiu reznicencu Apr 26 '19 at 10:39
  • What about the fixup table? How do you handle that? – rustyx Apr 26 '19 at 10:52
  • What...fixup? I will do some research. (you mean relocations? Because if you do then I handle it correctly. Actually this problematic-byte is the opcode and the next 4 bytes is the data. But it's just memory...it can't know what I intend to do with it. I am not executing that code, just modifying it ) – sergiu reznicencu Apr 26 '19 at 10:56
  • Yes relocations. Or link with /FIXED:YES. Also, check that VirtualProtect actually succeeded. – rustyx Apr 26 '19 at 11:00
  • Should I mention the entire code is debugged on a VM ? – sergiu reznicencu Apr 26 '19 at 11:01
  • Good ideea. I didn't check if VirtualProtect succeeded. I will test that – sergiu reznicencu Apr 26 '19 at 11:11
  • I don't understand. The address is there, I can see the entire memory, I can change everything I want, visual studio sees it , but despite all that the deferencing operator JUST returns 0xCC. Why? Can I debug visual studio itself? Perhpas it has something to do with casting? Perhaps unsigned/signed? I really don't know what to look for now. – sergiu reznicencu Apr 26 '19 at 11:20

1 Answers1

3

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.

Reznicencu Bogdan
  • 902
  • 2
  • 11
  • 28