Bug 1208944 - Part 4. nsWindowsDllInterceptor supports IMM32 API hook. r=ehsan

This commit is contained in:
Makoto Kato 2015-12-29 22:57:38 +09:00
parent bc73a806a2
commit cf7ec946b7
2 changed files with 105 additions and 31 deletions

View File

@ -159,6 +159,9 @@ int main()
TestHook("gdi32.dll", "CreateDIBSection") &&
TestHook("kernel32.dll", "CreateFileW") &&
#endif
TestHook("imm32.dll", "ImmGetContext") &&
TestHook("imm32.dll", "ImmGetCompositionStringW") &&
TestHook("imm32.dll", "ImmSetCandidateWindow") &&
TestDetour("ntdll.dll", "LdrLoadDll")) {
printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
return 0;

View File

@ -99,7 +99,7 @@ private:
class WindowsDllNopSpacePatcher
{
typedef unsigned char* byteptr_t;
typedef uint8_t* byteptr_t;
HMODULE mModule;
// Dumb array for remembering the addresses of functions we've patched.
@ -371,6 +371,66 @@ protected:
int mMaxHooks;
int mCurHooks;
#if defined(_M_X64)
// To patch for JMP and JE
enum JumpType {
Je,
Jmp
};
struct JumpPatch {
JumpPatch()
: mHookOffset(0), mJumpAddress(0), mType(JumpType::Jmp)
{
}
JumpPatch(size_t aOffset, intptr_t aAddress, JumpType aType = JumpType::Jmp)
: mHookOffset(aOffset), mJumpAddress(aAddress), mType(aType)
{
}
void AddJumpPatch(size_t aHookOffset, intptr_t aAbsJumpAddress,
JumpType aType = JumpType::Jmp)
{
mHookOffset = aHookOffset;
mJumpAddress = aAbsJumpAddress;
mType = aType;
}
size_t GenerateJump(uint8_t* aCode)
{
size_t offset = mHookOffset;
if (mType == JumpType::Je) {
// JNE RIP+14
aCode[offset] = 0x75;
aCode[offset + 1] = 14;
offset += 2;
}
// JMP [RIP+0]
aCode[offset] = 0xff;
aCode[offset + 1] = 0x25;
*reinterpret_cast<int32_t*>(aCode + offset + 2) = 0;
// Jump table
*reinterpret_cast<int64_t*>(aCode + offset + 2 + 4) = mJumpAddress;
return offset + 2 + 4 + 8;
}
bool HasJumpPatch() const
{
return !!mJumpAddress;
}
size_t mHookOffset;
intptr_t mJumpAddress;
JumpType mType;
};
#endif
void CreateTrampoline(void* aOrigFunction, intptr_t aDest, void** aOutTramp)
{
*aOutTramp = nullptr;
@ -383,9 +443,9 @@ protected:
byteptr_t origBytes = (byteptr_t)aOrigFunction;
int nBytes = 0;
int pJmp32 = -1;
#if defined(_M_IX86)
int pJmp32 = -1;
while (nBytes < 5) {
// Understand some simple instructions that might be found in a
// prologue; we might need to extend this as necessary.
@ -447,12 +507,12 @@ protected:
}
}
#elif defined(_M_X64)
byteptr_t directJmpAddr;
JumpPatch jump;
while (nBytes < 13) {
// if found JMP 32bit offset, next bytes must be NOP or INT3
if (pJmp32 >= 0) {
if (jump.HasJumpPatch()) {
if (origBytes[nBytes] == 0x90 || origBytes[nBytes] == 0xcc) {
nBytes++;
continue;
@ -473,6 +533,15 @@ protected:
} else if (origBytes[nBytes] == 0x05) {
// syscall
nBytes++;
} else if (origBytes[nBytes] == 0x84) {
// je rel32
jump.AddJumpPatch(nBytes - 1,
(intptr_t)
origBytes + nBytes + 5 +
*(reinterpret_cast<int32_t*>(origBytes +
nBytes + 1)),
JumpType::Je);
nBytes += 5;
} else {
return;
}
@ -516,6 +585,13 @@ protected:
(origBytes[nBytes + 1] & 0xf8) == 0x60) {
// and [r+d], imm8
nBytes += 5;
} else if (origBytes[nBytes] == 0x85) {
// 85 /r => TEST r/m32, r32
if ((origBytes[nBytes + 1] & 0xc0) == 0xc0) {
nBytes += 2;
} else {
return;
}
} else if ((origBytes[nBytes] & 0xfd) == 0x89) {
// MOV r/m64, r64 | MOV r64, r/m64
if ((origBytes[nBytes + 1] & 0xc0) == 0x40) {
@ -546,15 +622,16 @@ protected:
return;
}
} else if (origBytes[nBytes] == 0xff) {
pJmp32 = nBytes - 1;
// JMP /4
if ((origBytes[nBytes + 1] & 0xc0) == 0x0 &&
(origBytes[nBytes + 1] & 0x07) == 0x5) {
// [rip+disp32]
// convert JMP 32bit offset to JMP 64bit direct
directJmpAddr =
(byteptr_t)*((uint64_t*)(origBytes + nBytes + 6 +
(*((int32_t*)(origBytes + nBytes + 2)))));
jump.AddJumpPatch(nBytes - 1,
*reinterpret_cast<intptr_t*>(
origBytes + nBytes + 6 +
*reinterpret_cast<int32_t*>(origBytes + nBytes +
2)));
nBytes += 6;
} else {
// not support yet!
@ -576,11 +653,16 @@ protected:
} else if (origBytes[nBytes] == 0xc3) {
// ret
nBytes++;
} else if (origBytes[nBytes] == 0xcc) {
// int 3
nBytes++;
} else if (origBytes[nBytes] == 0xe9) {
pJmp32 = nBytes;
// convert JMP 32bit offset to JMP 64bit direct
directJmpAddr = origBytes + pJmp32 + 5 + (*((int32_t*)(origBytes + pJmp32 + 1)));
// jmp 32bit offset
jump.AddJumpPatch(nBytes,
// convert JMP 32bit offset to JMP 64bit direct
(intptr_t)
origBytes + nBytes + 5 +
*(reinterpret_cast<int32_t*>(origBytes + nBytes + 1)));
nBytes += 5;
} else if (origBytes[nBytes] == 0xff) {
nBytes++;
@ -625,27 +707,16 @@ protected:
(intptr_t)trampDest - (intptr_t)(tramp + nBytes + 5); // target displacement
}
#elif defined(_M_X64)
// If JMP32 opcode found, we don't insert to trampoline jump
if (pJmp32 >= 0) {
// mov r11, address
tramp[pJmp32] = 0x49;
tramp[pJmp32 + 1] = 0xbb;
*((intptr_t*)(tramp + pJmp32 + 2)) = (intptr_t)directJmpAddr;
// jmp r11
tramp[pJmp32 + 10] = 0x41;
tramp[pJmp32 + 11] = 0xff;
tramp[pJmp32 + 12] = 0xe3;
// If JMP/JE opcode found, we don't insert to trampoline jump
if (jump.HasJumpPatch()) {
size_t offset = jump.GenerateJump(tramp);
if (jump.mType != JumpType::Jmp) {
JumpPatch patch(offset, reinterpret_cast<intptr_t>(trampDest));
patch.GenerateJump(tramp);
}
} else {
// mov r11, address
tramp[nBytes] = 0x49;
tramp[nBytes + 1] = 0xbb;
*((intptr_t*)(tramp + nBytes + 2)) = (intptr_t)trampDest;
// jmp r11
tramp[nBytes + 10] = 0x41;
tramp[nBytes + 11] = 0xff;
tramp[nBytes + 12] = 0xe3;
JumpPatch patch(nBytes, reinterpret_cast<intptr_t>(trampDest));
patch.GenerateJump(tramp);
}
#endif