tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit df0b1573deb3d0ccf5d304bb77c35d66750f452b
parent ad700c2aa953d0ad201fa746c1c46257c9586cc3
Author: Greg Stoll <gstoll@mozilla.com>
Date:   Tue,  6 Jan 2026 14:36:18 +0000

Bug 2007585 - add a case for patching "and r, imm8" and similar instructions r=yjuglaret,win-reviewers

Trend Micro seems to patch NtReadFile before we get to it and inserts
one of these instructions. This change correctly patches this instruction.

Differential Revision: https://phabricator.services.mozilla.com/D277464

Diffstat:
Mtoolkit/xre/dllservices/mozglue/interceptor/PatcherDetour.h | 48+++++++++++++++++++++---------------------------
Mtoolkit/xre/dllservices/tests/AssemblyPayloads.h | 36++++++++++++++++++++++++++++++++++++
Mtoolkit/xre/dllservices/tests/TestDllInterceptor.cpp | 4++++
3 files changed, 61 insertions(+), 27 deletions(-)

diff --git a/toolkit/xre/dllservices/mozglue/interceptor/PatcherDetour.h b/toolkit/xre/dllservices/mozglue/interceptor/PatcherDetour.h @@ -1069,19 +1069,13 @@ class WindowsDllDetourPatcher final // INC r32 origBytes += 1; } else if (*origBytes == 0x83) { - uint8_t mod = static_cast<uint8_t>(origBytes[1]) & kMaskMod; - uint8_t rm = static_cast<uint8_t>(origBytes[1]) & kMaskRm; - if (mod == kModReg) { - // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP r, imm8 - origBytes += 3; - } else if (mod == kModDisp8 && rm != kRmNeedSib) { - // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP [r+disp8], imm8 - origBytes += 4; - } else { - // bail - MOZ_ASSERT_UNREACHABLE("Unrecognized bit opcode sequence"); + // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP on imm8 + int len = CountModRmSib(origBytes + 1); + if (len < 0) { + MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence"); return; } + COPY_CODES(len + 2); // 1 for 0x83, 1 for imm8 } else if (*origBytes == 0x68) { // PUSH with 4-byte operand origBytes += 5; @@ -1304,16 +1298,14 @@ class WindowsDllDetourPatcher final if (*origBytes == 0x81 && (origBytes[1] & 0xf8) == 0xe8) { // sub r, dword COPY_CODES(6); - } else if (*origBytes == 0x83 && (origBytes[1] & 0xf8) == 0xe8) { - // sub r, byte - COPY_CODES(3); - } else if (*origBytes == 0x83 && - (origBytes[1] & (kMaskMod | kMaskReg)) == kModReg) { - // add r, byte - COPY_CODES(3); - } else if (*origBytes == 0x83 && (origBytes[1] & 0xf8) == 0x60) { - // and [r+d], imm8 - COPY_CODES(5); + } else if (*origBytes == 0x83) { + // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP on imm8 + int len = CountModRmSib(origBytes + 1); + if (len < 0) { + MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence"); + return; + } + COPY_CODES(len + 2); // 1 for 0x83, 1 for imm8 } else if (*origBytes == 0x2b && (origBytes[1] & kMaskMod) == kModReg) { // sub r64, r64 COPY_CODES(2); @@ -1541,9 +1533,14 @@ class WindowsDllDetourPatcher final // 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 == 0x83 && (origBytes[1] & kMaskMod) == kModReg) { - // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP r, imm8 - COPY_CODES(3); + } else if (*origBytes == 0x83) { + // ADD|OR|ADC|SBB|AND|SUB|XOR|CMP on imm8 + int len = CountModRmSib(origBytes + 1); + if (len < 0) { + MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence"); + return; + } + COPY_CODES(len + 2); // 1 for 0x83, 1 for imm8 } else if (*origBytes == 0xc3) { // ret COPY_CODES(1); @@ -1645,9 +1642,6 @@ class WindowsDllDetourPatcher final MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence"); return; } - } else if (*origBytes == 0x83 && (origBytes[1] & 0xf8) == 0x60) { - // and [r+d], imm8 - COPY_CODES(5); } else if (*origBytes == 0xc6) { // mov [r+d], imm8 int len = CountModRmSib(origBytes + 1); diff --git a/toolkit/xre/dllservices/tests/AssemblyPayloads.h b/toolkit/xre/dllservices/tests/AssemblyPayloads.h @@ -158,6 +158,42 @@ __declspec(dllexport) MOZ_NAKED void MovImm64() { "nop;nop;nop"); } +__declspec(dllexport) MOZ_NAKED void AndWithSib() { + asm volatile( + "andl $15, (%%rax,%%rax,1);" // AND r/m32, imm32; + "nop;nop;nop;nop;nop;nop;nop;nop;nop;" + : + : + : "memory", "cc"); +} + +__declspec(dllexport) MOZ_NAKED void AndWithoutSib() { + asm volatile( + "andl $16, (%%rax);" // AND r/m32, imm32; + "nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;" + : + : + : "memory", "cc"); +} + +__declspec(dllexport) MOZ_NAKED void RexAndWithSib() { + asm volatile( + "andq $17, (%%r10,%%rcx,1);" // AND r/m64, imm8; + "nop;nop;nop;nop;nop;nop;nop;nop;" + : + : + : "memory", "cc"); +} + +__declspec(dllexport) MOZ_NAKED void RexAndWithoutSib() { + asm volatile( + "andq $18, (%%r10);" // AND r/m64, imm8 + "nop;nop;nop;nop;nop;nop;nop;nop;nop;" + : + : + : "memory", "cc"); +} + static unsigned char __attribute__((used)) gGlobalValue = 0; __declspec(dllexport) MOZ_NAKED void RexCmpRipRelativeBytePtr() { diff --git a/toolkit/xre/dllservices/tests/TestDllInterceptor.cpp b/toolkit/xre/dllservices/tests/TestDllInterceptor.cpp @@ -836,6 +836,10 @@ MOZ_GLOBINIT struct TestCase { TestCase("IndirectCall", NoStubAddressCheck), TestCase("MovImm64", NoStubAddressCheck), TestCase("RexCmpRipRelativeBytePtr", NoStubAddressCheck), + TestCase("AndWithSib", NoStubAddressCheck), + TestCase("AndWithoutSib", NoStubAddressCheck), + TestCase("RexAndWithSib", NoStubAddressCheck), + TestCase("RexAndWithoutSib", NoStubAddressCheck), TestCase("JmpInsideEarlyBytes", ExpectedFail), TestCase("CallInsideEarlyBytes", ExpectedFail), # elif defined(_M_IX86)