mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1208944 - Part 4. nsWindowsDllInterceptor supports IMM32 API hook. r=ehsan
This commit is contained in:
parent
e5533965df
commit
41219d5981
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user