Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.3k views
in Technique[技术] by (71.8m points)

c - Hot Patching A Function

I'm trying to hot patch an exe in memory, the source is available but I'm doing this for learning purposes. (so please no comments suggesting i modify the original source or use detours or any other libs)

Below are the functions I am having problems with.

vm_t* VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret )
{
    MessageBox(NULL, L"Oh snap! We hooked VM_Create!", L"Success!", MB_OK);
    return NULL;
}

void Hook_VM_Create(void)
{

    DWORD dwBackup;
    VirtualProtect((void*)0x00477C3E, 7, PAGE_EXECUTE_READWRITE, &dwBackup);

    //Patch the original VM_Create to jump to our detoured one.
    BYTE *jmp = (BYTE*)malloc(5);
    uint32_t offset = 0x00477C3E - (uint32_t)&VM_Create; //find the offset of the original function from our own
    memset((void*)jmp, 0xE9, 1);
    memcpy((void*)(jmp+1), &offset, sizeof(offset));
    memcpy((void*)0x00477C3E, jmp, 5);

    free(jmp);
}

I have a function VM_Create that I want to be called instead of the original function. I have not yet written a trampoline so it crashes (as expected). However the message box does not popup that I have detoured the original VM create to my own. I believe it is the way I'm overwriting the original instructions.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I can see a few issues.

I assume that 0x00477C3E is the address of the original VM_Create function. You really should not hard code this. Use &VM_Create instead. Of course this will mean that you need to use a different name for your replacement function.

The offset is calculated incorrectly. You have the sign wrong. What's more the offset is applied to the instruction pointer at the end of the instruction and not the beginning. So you need to shift it by 5 (the size of the instruction). The offset should be a signed integer also.

Ideally, if you take into account my first point the code would look like this:

int32_t offset = (int32_t)&New_VM_Create - ((int32_t)&VM_Create+5);

Thanks to Hans Passant for fixing my own silly sign error in the original version!

If you are working on a 64 bit machine you need to do your arithmetic in 64 bits and, once you have calculated the offset, truncate it to a 32 bit offset.

Another nuance is that you should reset the memory to being read-only after having written the new JMP instruction, and call FlushInstructionCache.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...