Bug 1367899: Add handling for test r/m32, r32 and jne rel8 opcodes; r?dmajor
MozReview-Commit-ID: 3Cnx5tYrqMT
--- a/xpcom/build/nsWindowsDllInterceptor.h
+++ b/xpcom/build/nsWindowsDllInterceptor.h
@@ -592,16 +592,17 @@ protected:
return numBytes;
}
#if defined(_M_X64)
// To patch for JMP and JE
enum JumpType {
Je,
+ Jne,
Jmp,
Call
};
struct JumpPatch {
JumpPatch()
: mHookOffset(0), mJumpAddress(0), mType(JumpType::Jmp)
{
@@ -615,16 +616,21 @@ protected:
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;
+ } else if (mType == JumpType::Jne) {
+ // JE RIP+14
+ aCode[offset] = 0x74;
+ aCode[offset + 1] = 14;
+ offset += 2;
}
// Near call/jmp, absolute indirect, address given in r/m32
if (mType == JumpType::Call) {
// CALL [RIP+0]
aCode[offset] = 0xff;
aCode[offset + 1] = 0x15;
// The offset to jump destination -- ie it is placed 2 bytes after the offset.
@@ -898,18 +904,18 @@ protected:
if (origBytes[nOrigBytes] == 0x33) {
// xor r32, r32
COPY_CODES(2);
} else {
MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence");
return;
}
- } else if ((origBytes[nOrigBytes] & 0xfb) == 0x48) {
- // REX.W | REX.WR
+ } else if ((origBytes[nOrigBytes] & 0xfa) == 0x48) {
+ // REX.W | REX.WR | REX.WRB | REX.WB
COPY_CODES(1);
if (origBytes[nOrigBytes] == 0x81 &&
(origBytes[nOrigBytes + 1] & 0xf8) == 0xe8) {
// sub r, dword
COPY_CODES(6);
} else if (origBytes[nOrigBytes] == 0x83 &&
(origBytes[nOrigBytes + 1] & 0xf8) == 0xe8) {
@@ -1119,16 +1125,24 @@ protected:
BYTE subOpcode = 0;
int nModRmSibBytes = CountModRmSib(&origBytes[nOrigBytes + 1], &subOpcode);
if (nModRmSibBytes < 0 || subOpcode != 0) {
// Unsupported
MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence");
return;
}
COPY_CODES(2 + nModRmSibBytes);
+ } else if (origBytes[nOrigBytes] == 0x85) {
+ // test r/m32, r32
+ int nModRmSibBytes = CountModRmSib(&origBytes[nOrigBytes + 1]);
+ if (nModRmSibBytes < 0) {
+ MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence");
+ return;
+ }
+ COPY_CODES(1 + nModRmSibBytes);
} else if (origBytes[nOrigBytes] == 0xd1 &&
(origBytes[nOrigBytes+1] & kMaskMod) == kModReg) {
// bit shifts/rotates : (SA|SH|RO|RC)(R|L) r32
// (e.g. 0xd1 0xe0 is SAL, 0xd1 0xc8 is ROR)
COPY_CODES(2);
} else if (origBytes[nOrigBytes] == 0xc3) {
// ret
COPY_CODES(1);
@@ -1140,16 +1154,26 @@ protected:
// CALL (0xe8) or JMP (0xe9) 32bit offset
foundJmp = origBytes[nOrigBytes] == 0xe9;
JumpPatch jump(nTrampBytes,
(intptr_t)(origBytes + nOrigBytes + 5 +
*(reinterpret_cast<int32_t*>(origBytes + nOrigBytes + 1))),
origBytes[nOrigBytes] == 0xe8 ? JumpType::Call : JumpType::Jmp);
nTrampBytes = jump.GenerateJump(tramp);
nOrigBytes += 5;
+ } else if (origBytes[nOrigBytes] == 0x74 || // je rel8 (0x74)
+ origBytes[nOrigBytes] == 0x75) { // jne rel8 (0x75)
+ char offset = origBytes[nOrigBytes + 1];
+ auto jumpType = JumpType::Je;
+ if (origBytes[nOrigBytes] == 0x75)
+ jumpType = JumpType::Jne;
+ JumpPatch jump(nTrampBytes,
+ (intptr_t)(origBytes + nOrigBytes + 2 + offset), jumpType);
+ nTrampBytes = jump.GenerateJump(tramp);
+ nOrigBytes += 2;
} else if (origBytes[nOrigBytes] == 0xff) {
if ((origBytes[nOrigBytes + 1] & (kMaskMod|kMaskReg)) == 0xf0) {
// push r64
COPY_CODES(2);
} else if (origBytes[nOrigBytes + 1] == 0x25) {
// jmp absolute indirect m32
foundJmp = true;
int32_t offset = *(reinterpret_cast<int32_t*>(origBytes + nOrigBytes + 2));