1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_interceptor_PatcherBase_h
8 #define mozilla_interceptor_PatcherBase_h
10 #include "mozilla/interceptor/TargetFunction.h"
13 namespace interceptor
{
15 template <typename MMPolicy
>
16 struct GetProcAddressSelector
;
19 struct GetProcAddressSelector
<MMPolicyOutOfProcess
> {
20 FARPROC
operator()(HMODULE aModule
, const char* aName
,
21 const MMPolicyOutOfProcess
& aMMPolicy
) const {
23 mozilla::nt::PEExportSection
<MMPolicyOutOfProcess
>::Get(aModule
,
25 return exportSection
.GetProcAddress(aName
);
30 struct GetProcAddressSelector
<MMPolicyInProcess
> {
31 FARPROC
operator()(HMODULE aModule
, const char* aName
,
32 const MMPolicyInProcess
&) const {
33 // PEExportSection works for MMPolicyInProcess, too, but the native
34 // GetProcAddress is still better because PEExportSection does not
35 // solve a forwarded entry.
36 return ::GetProcAddress(aModule
, aName
);
40 template <typename VMPolicy
>
41 class WindowsDllPatcherBase
{
43 typedef typename
VMPolicy::MMPolicyT MMPolicyT
;
45 template <typename
... Args
>
46 explicit WindowsDllPatcherBase(Args
&&... aArgs
)
47 : mVMPolicy(std::forward
<Args
>(aArgs
)...) {}
49 ReadOnlyTargetFunction
<MMPolicyT
> ResolveRedirectedAddress(
50 FARPROC aOriginalFunction
) {
51 uintptr_t currAddr
= reinterpret_cast<uintptr_t>(aOriginalFunction
);
53 #if defined(_M_IX86) || defined(_M_X64)
54 uintptr_t prevAddr
= 0;
55 while (prevAddr
!= currAddr
) {
56 ReadOnlyTargetFunction
<MMPolicyT
> currFunc(mVMPolicy
, currAddr
);
59 // If function entry is jmp rel8 stub to the internal implementation, we
60 // resolve redirected address from the jump target.
61 uintptr_t nextAddr
= 0;
62 if (currFunc
.IsRelativeShortJump(&nextAddr
)) {
63 int8_t offset
= nextAddr
- currFunc
.GetAddress() - 2;
66 // We redirect to the target of a short jump backwards if the target
67 // is another jump (only 32-bit displacement is currently supported).
68 // This case is used by GetFileAttributesW in Win7 x64.
69 if ((offset
< 0) && (currFunc
.IsValidAtOffset(2 + offset
))) {
70 ReadOnlyTargetFunction
<MMPolicyT
> redirectFn(mVMPolicy
, nextAddr
);
71 if (redirectFn
.IsIndirectNearJump(&nextAddr
)) {
77 // We check the downstream has enough nop-space only when the offset is
78 // positive. Otherwise we stop chasing redirects and let the caller
81 bool isNopSpace
= true;
82 for (int8_t i
= 0; i
< offset
; i
++) {
83 if (currFunc
[2 + i
] != 0x90) {
94 } else if (currFunc
.IsIndirectNearJump(&nextAddr
) ||
95 currFunc
.IsRelativeNearJump(&nextAddr
)) {
97 } else if (currFunc
.IsIndirectNearJump(&nextAddr
)) {
99 // If function entry is jmp [disp32] such as used by kernel32, we
100 // resolve redirected address from import table. For x64, we resolve
101 // a relative near jump for TestDllInterceptor with --disable-optimize.
105 #endif // defined(_M_IX86) || defined(_M_X64)
107 if (currAddr
!= reinterpret_cast<uintptr_t>(aOriginalFunction
) &&
108 !mVMPolicy
.IsPageAccessible(currAddr
)) {
109 currAddr
= reinterpret_cast<uintptr_t>(aOriginalFunction
);
111 return ReadOnlyTargetFunction
<MMPolicyT
>(mVMPolicy
, currAddr
);
115 FARPROC
GetProcAddress(HMODULE aModule
, const char* aName
) const {
116 GetProcAddressSelector
<MMPolicyT
> selector
;
117 return selector(aModule
, aName
, mVMPolicy
);
120 bool IsPageAccessible(uintptr_t aAddress
) const {
121 return mVMPolicy
.IsPageAccessible(aAddress
);
124 #if defined(NIGHTLY_BUILD)
125 const Maybe
<DetourError
>& GetLastDetourError() const {
126 return mVMPolicy
.GetLastDetourError();
128 #endif // defined(NIGHTLY_BUILD)
129 template <typename
... Args
>
130 void SetLastDetourError(Args
&&... aArgs
) {
131 mVMPolicy
.SetLastDetourError(std::forward
<Args
>(aArgs
)...);
138 } // namespace interceptor
139 } // namespace mozilla
141 #endif // mozilla_interceptor_PatcherBase_h