Valhalla Legends Forums Archive | C/C++ Programming | Inspecting/Rewriting code segment memory at runtime

AuthorMessageTime
Myndfyr
I'm toying around at work with VC++ and runtime code re-writing (for code protection), and wanted to know a few things...

1.) Will I need to mark the virtual code segment readable/writeable?  I'm trying to just print out memory byte-by-byte and I got the following runtime error:
[code]
First-chance exception at 0x0041b4a2 in CrackMe1.exe: 0xC0000005: Access violation reading location 0x0025fb58.
Unhandled exception at 0x0041b4a2 in CrackMe1.exe: 0xC0000005: Access violation reading location 0x0025fb58.
[/code]
2.) Am I using the right types?

Here's what I have so far (types can be inferred, these are the main functions that I'm using):
[code]
int _tmain(int argc, _TCHAR* argv[])
{
char *psz_inbuf;
DWORD *pnLabelLoc;
DWORD *pnEndLoc;
DWORD nDiff;

__asm   push ecx

psz_inbuf = new char[20];

do
{
cout << "Enter password: " << endl;
psz_inbuf = gets(psz_inbuf);
} while (psz_inbuf == NULL);

cout << "Memory location: " << &psz_inbuf << endl;

_asm
{
xor ecx, ecx
mov ecx, dword ptr checking_code
mov pnLabelLoc, ecx
mov ecx, dword ptr end_checking_code
mov pnEndLoc, ecx
}
cout << "Label location: " << pnLabelLoc << endl;
cout << "End location: " << pnEndLoc << endl;
nDiff = (BYTE)pnEndLoc - (BYTE)pnLabelLoc;
cout << "Difference: " << nDiff << endl;

print( (BYTE*)pnLabelLoc, nDiff );

getchar();

__asm
{
checking_code:
xor ecx, ecx
inc ecx

end_checking_code:
inc ecx
}

__asm   pop ecx
return 0;
}

inline void print(const BYTE *pMem, const DWORD nLen)
{
DWORD nMem, nVal;
cout << "Data from pnLabelLoc to pnEndLoc:" << endl;

__asm   push edx
for (DWORD i = 0; i < nLen; i++)
{
__asm   mov edx, pMem
__asm   add     edx, i
__asm   mov nMem, edx
__asm   xor edx, edx
__asm   mov dl, byte ptr [pMem + i]
__asm   mov     nVal, edx
cout << "[" << nMem << "]: " << nVal << endl;
}

__asm   pop edx
}
[/code]

And this is the complete output:
[code]
Enter password:
sgfe
Memory location: 0012FED4
Label location: 0041B374
End location: 0041B377
Difference: 3
Data from pnLabelLoc to pnEndLoc:
[/code]

I don't know whether or not I should be taking care of storing register contents.  All I know is that when I took assembly, they told us that we should store register contents.  I realize I'm using C as opposed to pure assembly, so if I shouldn't be doing that, give me a heads-up.

This is the offending line, from print(BYTE *, DWORD):
[code]
__asm   mov dl, byte ptr [pMem + i]
[/code]
So I assume that code memory is not readable?

Basically, I want to print the memory byte-by-byte between the checking_code and end_checking_code labels.  I wanted to do this as an inline function so I could look at the result disassembly and see if it is any more difficult to read.  Of course, that assumes the compiler obeys inline.

The ultimate goal is to be able to read and write to arbitrary memory within the program's virtual memory space -- not violating any kernel rules, but being able to rewrite code on the fly as well as data.

Any thoughts?
March 31, 2005, 2:11 AM
Adron
[quote author=MyndFyre link=topic=11109.msg106448#msg106448 date=1112235111]
1.) Will I need to mark the virtual code segment readable/writeable? 
[/quote]

In Win32 it is readable but not writeable by default.


[quote author=MyndFyre link=topic=11109.msg106448#msg106448 date=1112235111]
This is the offending line, from print(BYTE *, DWORD):
[code]
__asm   mov dl, byte ptr [pMem + i]
[/code]
So I assume that code memory is not readable?
[/quote]

It is readable. You're just not reading the right memory. You get an error reading from 0x25fb58, and that's not the location of your code. I don't see why you're doing this in assembly, as it would make much more sense to do it in plain C/C++. Your problems are with your implementation of this in assembler.

For one, yes, you should save most registers. But you should save them before you modify them and restore them before you return to executing C/C++ code. As you have it now, you are modifying esp and edx and then executing C/C++ code before you have restored them. Rewrite print without any assembler use and it'll work much better.

I don't know exactly what is wrong with your print function - could be that edx/esp are used by the compiler for something and you're messing it up, or it could be the way "mov dl, byte ptr [pMem + i]" is written. It's not obvious to me why you'd get a pointer so far into nothingness but it probably would be if I was looking at the generated code for it. What you're doing there is wrong unless both pMem and i are available in registers and even then, the compiler probably won't do what you're expecting of it. 

March 31, 2005, 8:44 AM
Myndfyr
OK -- I updated the print function to remove the inline assembly.  Here it is:

[code]
inline void print(const BYTE *pMem, const DWORD nLen)
{
cout << "Data from pnLabelLoc to pnEndLoc:" << endl;

for (DWORD i = 0; i < nLen; i++)
{
cout << "[" << ((DWORD)(pMem + i)) << "]: " << ((int)*(pMem + i)) << endl;
}

}
[/code]

and here is the revised output:

[code]
Enter password:
dgzh
Memory location: 0012FED4
Label location: 0041B364
End location: 0041B367
Difference: 3
Data from pnLabelLoc to pnEndLoc:
[4305764]: 51
[4305765]: 201
[4305766]: 65
[/code]
Intuition tells me that the first memory location is in the data segment, where it's storing the string.  Also, cout is data-type specific, so both values are in decimal instead of hex -- the memory location is correct, if I am indeed obtaining the address of the labels.  And I couldn't pass the pointer to cout, as it would try to print the data like a string.  So I cast it back to a numeric value.  Because of the casts, I'm getting this warning:
[code]warning C4311: 'type cast' : pointer truncation from 'const BYTE *' to 'DWORD'[/code]
But it appears to work.

Adron -- how can I mark a section writeable?

[edit]
I did an opcode lookup using the IA32 manual #2.  The output was:
[4305764]: 51
[4305765]: 201
[4305766]: 65
51 = 0x33, which is XOR Gb, Ev.  This is what the manual says for E notes:
[quote]A ModR/M byte follows the opcode and specifies the operand. The operand is either a general-purpose register or a memory address. If it is a memory address, the address is computed from a segment register and any of the following values: a base register, an index register, a scaling factor, a displacement.[/quote]
Of G: [quote]The reg field of the ModR/M byte selects a general register (for example, AX (000)).[/quote]
The 201 value, or 0xc9, is represented 1100 1001 in binary.  Split as the ModR/M byte -- 11 001 001, the middle value indicates that it's ECX.  I can't find the meaning of the rest of the bits -- any ideas?
Finally, 65, or 0x41, is easily looked up as INC ECX.

So it turns out I *was* looking at the right spot in memory or, short of that, got REALLY lucky!
April 1, 2005, 2:26 AM
Arta
VirtualProtect/VirtualProtectEx, with PAGE_EXECUTE_READWRITE. I set mine back to PAGE_EXECUTE_READ when I'm done, because making executable pages read-only is a sensible precaution.
April 1, 2005, 2:30 AM
Adron
[quote author=MyndFyre link=topic=11109.msg106668#msg106668 date=1112322392]
Intuition tells me that the first memory location is in the data segment, where it's storing the string.
[/quote]

It's actually in the stack, where it's storing the pointer to the string.


[quote author=MyndFyre link=topic=11109.msg106668#msg106668 date=1112322392]
Split as the ModR/M byte -- 11 001 001, the middle value indicates that it's ECX.  I can't find the meaning of the rest of the bits -- any ideas?
[/quote]

Mod = 11: Both operands are registers
Reg = 001: CL/CX/ECX
R/M = 001: CL/CX/ECX

April 1, 2005, 8:39 AM

Search