1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/win/iat_patch_function.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr_exclusion.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/win/patch_util.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/win/pe_image.h"
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker namespace base {
14*6777b538SAndroid Build Coastguard Worker namespace win {
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Worker namespace {
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker struct InterceptFunctionInformation {
19*6777b538SAndroid Build Coastguard Worker bool finished_operation;
20*6777b538SAndroid Build Coastguard Worker const char* imported_from_module;
21*6777b538SAndroid Build Coastguard Worker const char* function_name;
22*6777b538SAndroid Build Coastguard Worker // RAW_PTR_EXCLUSION: #reinterpret-cast-trivial-type
23*6777b538SAndroid Build Coastguard Worker RAW_PTR_EXCLUSION void* new_function;
24*6777b538SAndroid Build Coastguard Worker RAW_PTR_EXCLUSION void** old_function;
25*6777b538SAndroid Build Coastguard Worker RAW_PTR_EXCLUSION IMAGE_THUNK_DATA** iat_thunk;
26*6777b538SAndroid Build Coastguard Worker DWORD return_code;
27*6777b538SAndroid Build Coastguard Worker };
28*6777b538SAndroid Build Coastguard Worker
GetIATFunction(IMAGE_THUNK_DATA * iat_thunk)29*6777b538SAndroid Build Coastguard Worker void* GetIATFunction(IMAGE_THUNK_DATA* iat_thunk) {
30*6777b538SAndroid Build Coastguard Worker if (!iat_thunk) {
31*6777b538SAndroid Build Coastguard Worker NOTREACHED();
32*6777b538SAndroid Build Coastguard Worker return nullptr;
33*6777b538SAndroid Build Coastguard Worker }
34*6777b538SAndroid Build Coastguard Worker
35*6777b538SAndroid Build Coastguard Worker // Works around the 64 bit portability warning:
36*6777b538SAndroid Build Coastguard Worker // The Function member inside IMAGE_THUNK_DATA is really a pointer
37*6777b538SAndroid Build Coastguard Worker // to the IAT function. IMAGE_THUNK_DATA correctly maps to IMAGE_THUNK_DATA32
38*6777b538SAndroid Build Coastguard Worker // or IMAGE_THUNK_DATA64 for correct pointer size.
39*6777b538SAndroid Build Coastguard Worker union FunctionThunk {
40*6777b538SAndroid Build Coastguard Worker IMAGE_THUNK_DATA thunk;
41*6777b538SAndroid Build Coastguard Worker // This field is not a raw_ptr<> because it was filtered by the rewriter
42*6777b538SAndroid Build Coastguard Worker // for: #union
43*6777b538SAndroid Build Coastguard Worker RAW_PTR_EXCLUSION void* pointer;
44*6777b538SAndroid Build Coastguard Worker } iat_function;
45*6777b538SAndroid Build Coastguard Worker
46*6777b538SAndroid Build Coastguard Worker iat_function.thunk = *iat_thunk;
47*6777b538SAndroid Build Coastguard Worker return iat_function.pointer;
48*6777b538SAndroid Build Coastguard Worker }
49*6777b538SAndroid Build Coastguard Worker
InterceptEnumCallback(const base::win::PEImage & image,const char * module,DWORD ordinal,const char * name,DWORD hint,IMAGE_THUNK_DATA * iat,void * cookie)50*6777b538SAndroid Build Coastguard Worker bool InterceptEnumCallback(const base::win::PEImage& image,
51*6777b538SAndroid Build Coastguard Worker const char* module,
52*6777b538SAndroid Build Coastguard Worker DWORD ordinal,
53*6777b538SAndroid Build Coastguard Worker const char* name,
54*6777b538SAndroid Build Coastguard Worker DWORD hint,
55*6777b538SAndroid Build Coastguard Worker IMAGE_THUNK_DATA* iat,
56*6777b538SAndroid Build Coastguard Worker void* cookie) {
57*6777b538SAndroid Build Coastguard Worker InterceptFunctionInformation* intercept_information =
58*6777b538SAndroid Build Coastguard Worker reinterpret_cast<InterceptFunctionInformation*>(cookie);
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker if (!intercept_information) {
61*6777b538SAndroid Build Coastguard Worker NOTREACHED();
62*6777b538SAndroid Build Coastguard Worker return false;
63*6777b538SAndroid Build Coastguard Worker }
64*6777b538SAndroid Build Coastguard Worker
65*6777b538SAndroid Build Coastguard Worker DCHECK(module);
66*6777b538SAndroid Build Coastguard Worker
67*6777b538SAndroid Build Coastguard Worker if (name && (0 == lstrcmpiA(name, intercept_information->function_name))) {
68*6777b538SAndroid Build Coastguard Worker // Save the old pointer.
69*6777b538SAndroid Build Coastguard Worker if (intercept_information->old_function) {
70*6777b538SAndroid Build Coastguard Worker *(intercept_information->old_function) = GetIATFunction(iat);
71*6777b538SAndroid Build Coastguard Worker }
72*6777b538SAndroid Build Coastguard Worker
73*6777b538SAndroid Build Coastguard Worker if (intercept_information->iat_thunk) {
74*6777b538SAndroid Build Coastguard Worker *(intercept_information->iat_thunk) = iat;
75*6777b538SAndroid Build Coastguard Worker }
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Worker // portability check
78*6777b538SAndroid Build Coastguard Worker static_assert(
79*6777b538SAndroid Build Coastguard Worker sizeof(iat->u1.Function) == sizeof(intercept_information->new_function),
80*6777b538SAndroid Build Coastguard Worker "unknown IAT thunk format");
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker // Patch the function.
83*6777b538SAndroid Build Coastguard Worker intercept_information->return_code = internal::ModifyCode(
84*6777b538SAndroid Build Coastguard Worker &(iat->u1.Function), &(intercept_information->new_function),
85*6777b538SAndroid Build Coastguard Worker sizeof(intercept_information->new_function));
86*6777b538SAndroid Build Coastguard Worker
87*6777b538SAndroid Build Coastguard Worker // Terminate further enumeration.
88*6777b538SAndroid Build Coastguard Worker intercept_information->finished_operation = true;
89*6777b538SAndroid Build Coastguard Worker return false;
90*6777b538SAndroid Build Coastguard Worker }
91*6777b538SAndroid Build Coastguard Worker
92*6777b538SAndroid Build Coastguard Worker return true;
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker // Helper to intercept a function in an import table of a specific
96*6777b538SAndroid Build Coastguard Worker // module.
97*6777b538SAndroid Build Coastguard Worker //
98*6777b538SAndroid Build Coastguard Worker // Arguments:
99*6777b538SAndroid Build Coastguard Worker // module_handle Module to be intercepted
100*6777b538SAndroid Build Coastguard Worker // imported_from_module Module that exports the symbol
101*6777b538SAndroid Build Coastguard Worker // function_name Name of the API to be intercepted
102*6777b538SAndroid Build Coastguard Worker // new_function Interceptor function
103*6777b538SAndroid Build Coastguard Worker // old_function Receives the original function pointer
104*6777b538SAndroid Build Coastguard Worker // iat_thunk Receives pointer to IAT_THUNK_DATA
105*6777b538SAndroid Build Coastguard Worker // for the API from the import table.
106*6777b538SAndroid Build Coastguard Worker //
107*6777b538SAndroid Build Coastguard Worker // Returns: Returns NO_ERROR on success or Windows error code
108*6777b538SAndroid Build Coastguard Worker // as defined in winerror.h
InterceptImportedFunction(HMODULE module_handle,const char * imported_from_module,const char * function_name,void * new_function,void ** old_function,IMAGE_THUNK_DATA ** iat_thunk)109*6777b538SAndroid Build Coastguard Worker DWORD InterceptImportedFunction(HMODULE module_handle,
110*6777b538SAndroid Build Coastguard Worker const char* imported_from_module,
111*6777b538SAndroid Build Coastguard Worker const char* function_name,
112*6777b538SAndroid Build Coastguard Worker void* new_function,
113*6777b538SAndroid Build Coastguard Worker void** old_function,
114*6777b538SAndroid Build Coastguard Worker IMAGE_THUNK_DATA** iat_thunk) {
115*6777b538SAndroid Build Coastguard Worker if (!module_handle || !imported_from_module || !function_name ||
116*6777b538SAndroid Build Coastguard Worker !new_function) {
117*6777b538SAndroid Build Coastguard Worker NOTREACHED();
118*6777b538SAndroid Build Coastguard Worker return ERROR_INVALID_PARAMETER;
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker base::win::PEImage target_image(module_handle);
122*6777b538SAndroid Build Coastguard Worker if (!target_image.VerifyMagic()) {
123*6777b538SAndroid Build Coastguard Worker NOTREACHED();
124*6777b538SAndroid Build Coastguard Worker return ERROR_INVALID_PARAMETER;
125*6777b538SAndroid Build Coastguard Worker }
126*6777b538SAndroid Build Coastguard Worker
127*6777b538SAndroid Build Coastguard Worker InterceptFunctionInformation intercept_information = {false,
128*6777b538SAndroid Build Coastguard Worker imported_from_module,
129*6777b538SAndroid Build Coastguard Worker function_name,
130*6777b538SAndroid Build Coastguard Worker new_function,
131*6777b538SAndroid Build Coastguard Worker old_function,
132*6777b538SAndroid Build Coastguard Worker iat_thunk,
133*6777b538SAndroid Build Coastguard Worker ERROR_GEN_FAILURE};
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker // First go through the IAT. If we don't find the import we are looking
136*6777b538SAndroid Build Coastguard Worker // for in IAT, search delay import table.
137*6777b538SAndroid Build Coastguard Worker target_image.EnumAllImports(InterceptEnumCallback, &intercept_information,
138*6777b538SAndroid Build Coastguard Worker imported_from_module);
139*6777b538SAndroid Build Coastguard Worker if (!intercept_information.finished_operation) {
140*6777b538SAndroid Build Coastguard Worker target_image.EnumAllDelayImports(
141*6777b538SAndroid Build Coastguard Worker InterceptEnumCallback, &intercept_information, imported_from_module);
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Worker return intercept_information.return_code;
145*6777b538SAndroid Build Coastguard Worker }
146*6777b538SAndroid Build Coastguard Worker
147*6777b538SAndroid Build Coastguard Worker // Restore intercepted IAT entry with the original function.
148*6777b538SAndroid Build Coastguard Worker //
149*6777b538SAndroid Build Coastguard Worker // Arguments:
150*6777b538SAndroid Build Coastguard Worker // intercept_function Interceptor function
151*6777b538SAndroid Build Coastguard Worker // original_function Receives the original function pointer
152*6777b538SAndroid Build Coastguard Worker //
153*6777b538SAndroid Build Coastguard Worker // Returns: Returns NO_ERROR on success or Windows error code
154*6777b538SAndroid Build Coastguard Worker // as defined in winerror.h
RestoreImportedFunction(void * intercept_function,void * original_function,IMAGE_THUNK_DATA * iat_thunk)155*6777b538SAndroid Build Coastguard Worker DWORD RestoreImportedFunction(void* intercept_function,
156*6777b538SAndroid Build Coastguard Worker void* original_function,
157*6777b538SAndroid Build Coastguard Worker IMAGE_THUNK_DATA* iat_thunk) {
158*6777b538SAndroid Build Coastguard Worker if (!intercept_function || !original_function || !iat_thunk) {
159*6777b538SAndroid Build Coastguard Worker NOTREACHED();
160*6777b538SAndroid Build Coastguard Worker return ERROR_INVALID_PARAMETER;
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker
163*6777b538SAndroid Build Coastguard Worker if (GetIATFunction(iat_thunk) != intercept_function) {
164*6777b538SAndroid Build Coastguard Worker // Check if someone else has intercepted on top of us.
165*6777b538SAndroid Build Coastguard Worker // We cannot unpatch in this case, just raise a red flag.
166*6777b538SAndroid Build Coastguard Worker NOTREACHED();
167*6777b538SAndroid Build Coastguard Worker return ERROR_INVALID_FUNCTION;
168*6777b538SAndroid Build Coastguard Worker }
169*6777b538SAndroid Build Coastguard Worker
170*6777b538SAndroid Build Coastguard Worker return internal::ModifyCode(&(iat_thunk->u1.Function), &original_function,
171*6777b538SAndroid Build Coastguard Worker sizeof(original_function));
172*6777b538SAndroid Build Coastguard Worker }
173*6777b538SAndroid Build Coastguard Worker
174*6777b538SAndroid Build Coastguard Worker } // namespace
175*6777b538SAndroid Build Coastguard Worker
176*6777b538SAndroid Build Coastguard Worker IATPatchFunction::IATPatchFunction() = default;
177*6777b538SAndroid Build Coastguard Worker
~IATPatchFunction()178*6777b538SAndroid Build Coastguard Worker IATPatchFunction::~IATPatchFunction() {
179*6777b538SAndroid Build Coastguard Worker if (intercept_function_) {
180*6777b538SAndroid Build Coastguard Worker DWORD error = Unpatch();
181*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
182*6777b538SAndroid Build Coastguard Worker }
183*6777b538SAndroid Build Coastguard Worker }
184*6777b538SAndroid Build Coastguard Worker
Patch(const wchar_t * module,const char * imported_from_module,const char * function_name,void * new_function)185*6777b538SAndroid Build Coastguard Worker DWORD IATPatchFunction::Patch(const wchar_t* module,
186*6777b538SAndroid Build Coastguard Worker const char* imported_from_module,
187*6777b538SAndroid Build Coastguard Worker const char* function_name,
188*6777b538SAndroid Build Coastguard Worker void* new_function) {
189*6777b538SAndroid Build Coastguard Worker HMODULE module_handle = LoadLibraryW(module);
190*6777b538SAndroid Build Coastguard Worker if (!module_handle) {
191*6777b538SAndroid Build Coastguard Worker NOTREACHED();
192*6777b538SAndroid Build Coastguard Worker return GetLastError();
193*6777b538SAndroid Build Coastguard Worker }
194*6777b538SAndroid Build Coastguard Worker
195*6777b538SAndroid Build Coastguard Worker DWORD error = PatchFromModule(module_handle, imported_from_module,
196*6777b538SAndroid Build Coastguard Worker function_name, new_function);
197*6777b538SAndroid Build Coastguard Worker if (NO_ERROR == error) {
198*6777b538SAndroid Build Coastguard Worker module_handle_ = module_handle;
199*6777b538SAndroid Build Coastguard Worker } else {
200*6777b538SAndroid Build Coastguard Worker FreeLibrary(module_handle);
201*6777b538SAndroid Build Coastguard Worker }
202*6777b538SAndroid Build Coastguard Worker
203*6777b538SAndroid Build Coastguard Worker return error;
204*6777b538SAndroid Build Coastguard Worker }
205*6777b538SAndroid Build Coastguard Worker
PatchFromModule(HMODULE module,const char * imported_from_module,const char * function_name,void * new_function)206*6777b538SAndroid Build Coastguard Worker DWORD IATPatchFunction::PatchFromModule(HMODULE module,
207*6777b538SAndroid Build Coastguard Worker const char* imported_from_module,
208*6777b538SAndroid Build Coastguard Worker const char* function_name,
209*6777b538SAndroid Build Coastguard Worker void* new_function) {
210*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(nullptr, original_function_);
211*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(nullptr, iat_thunk_);
212*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(nullptr, intercept_function_);
213*6777b538SAndroid Build Coastguard Worker DCHECK(module);
214*6777b538SAndroid Build Coastguard Worker
215*6777b538SAndroid Build Coastguard Worker DWORD error = InterceptImportedFunction(
216*6777b538SAndroid Build Coastguard Worker module, imported_from_module, function_name, new_function,
217*6777b538SAndroid Build Coastguard Worker &original_function_.AsEphemeralRawAddr(),
218*6777b538SAndroid Build Coastguard Worker &iat_thunk_.AsEphemeralRawAddr());
219*6777b538SAndroid Build Coastguard Worker
220*6777b538SAndroid Build Coastguard Worker if (NO_ERROR == error) {
221*6777b538SAndroid Build Coastguard Worker DCHECK_NE(original_function_, intercept_function_);
222*6777b538SAndroid Build Coastguard Worker intercept_function_ = new_function;
223*6777b538SAndroid Build Coastguard Worker }
224*6777b538SAndroid Build Coastguard Worker
225*6777b538SAndroid Build Coastguard Worker return error;
226*6777b538SAndroid Build Coastguard Worker }
227*6777b538SAndroid Build Coastguard Worker
Unpatch()228*6777b538SAndroid Build Coastguard Worker DWORD IATPatchFunction::Unpatch() {
229*6777b538SAndroid Build Coastguard Worker DWORD error = RestoreImportedFunction(intercept_function_, original_function_,
230*6777b538SAndroid Build Coastguard Worker iat_thunk_);
231*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
232*6777b538SAndroid Build Coastguard Worker
233*6777b538SAndroid Build Coastguard Worker // Hands off the intercept if we fail to unpatch.
234*6777b538SAndroid Build Coastguard Worker // If IATPatchFunction::Unpatch fails during RestoreImportedFunction
235*6777b538SAndroid Build Coastguard Worker // it means that we cannot safely unpatch the import address table
236*6777b538SAndroid Build Coastguard Worker // patch. In this case its better to be hands off the intercept as
237*6777b538SAndroid Build Coastguard Worker // trying to unpatch again in the destructor of IATPatchFunction is
238*6777b538SAndroid Build Coastguard Worker // not going to be any safer
239*6777b538SAndroid Build Coastguard Worker if (module_handle_)
240*6777b538SAndroid Build Coastguard Worker FreeLibrary(module_handle_);
241*6777b538SAndroid Build Coastguard Worker module_handle_ = nullptr;
242*6777b538SAndroid Build Coastguard Worker intercept_function_ = nullptr;
243*6777b538SAndroid Build Coastguard Worker original_function_ = nullptr;
244*6777b538SAndroid Build Coastguard Worker iat_thunk_ = nullptr;
245*6777b538SAndroid Build Coastguard Worker
246*6777b538SAndroid Build Coastguard Worker return error;
247*6777b538SAndroid Build Coastguard Worker }
248*6777b538SAndroid Build Coastguard Worker
original_function() const249*6777b538SAndroid Build Coastguard Worker void* IATPatchFunction::original_function() const {
250*6777b538SAndroid Build Coastguard Worker DCHECK(is_patched());
251*6777b538SAndroid Build Coastguard Worker return original_function_;
252*6777b538SAndroid Build Coastguard Worker }
253*6777b538SAndroid Build Coastguard Worker
254*6777b538SAndroid Build Coastguard Worker } // namespace win
255*6777b538SAndroid Build Coastguard Worker } // namespace base
256