// The InterceptionManager executes on the parent application, and it is in // charge of setting up the desired interceptions, and placing the Interception // Agent into the child application. // 这是个泛用说法,对应chrome,parent就是broker,child主要是renderer(target)。 // broker上运行的InterceptionManager实例负责安装Interception Agent到renderer上 // // The exposed API consists of two methods: AddToPatchedFunctions to set up a // particular interception, and InitializeInterceptions to actually go ahead and // perform all interceptions and transfer data to the child application. // // The typical usage is something like this: // // InterceptionManager interception_manager(child); // if (!interception_manager.AddToPatchedFunctions( // L"ntdll.dll", "NtCreateFile", // sandbox::INTERCEPTION_SERVICE_CALL, &MyNtCreateFile, MY_ID_1)) // return false; // // if (!interception_manager.AddToPatchedFunctions( // L"kernel32.dll", "CreateDirectoryW", // sandbox::INTERCEPTION_EAT, L"MyCreateDirectoryW@12", MY_ID_2)) // return false; // // sandbox::ResultCode rc = interception_manager.InitializeInterceptions(); // if (rc != sandbox::SBOX_ALL_OK) { // DWORD error = ::GetLastError(); // return rc; // } // Add->Add->Add->...->Init一波流 // // Any required syncronization must be performed outside this class. Also, it is // not possible to perform further interceptions after InitializeInterceptions // is called. // 一旦InitializeInterceptions后,就不能再添加interceptions了 classInterceptionManager { // The unit test will access private members. // Allow tests to be marked DISABLED_. Note that FLAKY_ and FAILS_ prefixes // do not work with sandbox tests. // 单元测试的批量友元类,为了访问private,常见套路,这里不关心 FRIEND_TEST_ALL_PREFIXES(InterceptionManagerTest, BufferLayout1); FRIEND_TEST_ALL_PREFIXES(InterceptionManagerTest, BufferLayout2);
public: // An interception manager performs interceptions on a given child process. // If we are allowed to intercept functions that have been patched by somebody // else, relaxed should be set to true. // Note: We increase the child's reference count internally. // 构造器关联了TargetProcess对象 // 如果relaxed置true则表示可以覆盖别人的patch InterceptionManager(TargetProcess* child_process, bool relaxed); ~InterceptionManager();
// Patches function_name inside dll_name to point to replacement_code_address. // function_name has to be an exported symbol of dll_name. // Returns true on success. // // The new function should match the prototype and calling convention of the // function to intercept except for one extra argument (the first one) that // contains a pointer to the original function, to simplify the development // of interceptors (for IA32). In x64, there is no extra argument to the // interceptor, so the provided InterceptorId is used to keep a table of // intercepted functions so that the interceptor can index that table to get // the pointer that would have been the first argument (g_originals[id]). // // For example, to intercept NtClose, the following code could be used: // x86和x64对hook函数的不同处理 // 下面给了一个对NtCloseFunction进行hook的方式,增加了一个原始函数指针的参数 // typedef NTSTATUS (WINAPI *NtCloseFunction) (IN HANDLE Handle); // NTSTATUS WINAPI MyNtCose(IN NtCloseFunction OriginalClose, // IN HANDLE Handle) { // // do something // // call the original function // return OriginalClose(Handle); // } // // And in x64: // x64没有传参,而是使用了g_originals全局函数指针表 // typedef NTSTATUS (WINAPI *NtCloseFunction) (IN HANDLE Handle); // NTSTATUS WINAPI MyNtCose64(IN HANDLE Handle) { // // do something // // call the original function // NtCloseFunction OriginalClose = g_originals[NT_CLOSE_ID]; // return OriginalClose(Handle); // } // add方法的几种重载 // 这个是把function_name的函数指针替换成replacement_code_address起始的地址 boolAddToPatchedFunctions(constwchar_t* dll_name, constchar* function_name, InterceptionType interception_type, constvoid* replacement_code_address, InterceptorId id);
// Patches function_name inside dll_name to point to // replacement_function_name. // 用replacement_function_name来替换function_name boolAddToPatchedFunctions(constwchar_t* dll_name, constchar* function_name, InterceptionType interception_type, constchar* replacement_function_name, InterceptorId id);
// The interception agent will unload the dll with dll_name. // unload dll boolAddToUnloadModules(constwchar_t* dll_name);
// Initializes all interceptions on the client. // Returns SBOX_ALL_OK on success, or an appropriate error code. // // The child process must be created suspended, and cannot be resumed until // after this method returns. In addition, no action should be performed on // the child that may cause it to resume momentarily, such as injecting // threads or APCs. // // This function must be called only once, after all interceptions have been // set up using AddToPatchedFunctions. // 这个就是最后的fire ResultCode InitializeInterceptions();
private: // Used to store the interception information until the actual set-up. structInterceptionData { InterceptionData(); InterceptionData(const InterceptionData& other); ~InterceptionData();
//这两个都是枚举量,id主要是用于划分给不同Dispatcher,type是某一种拦截类型 //这个结构体把所有有用的信息都封装好了 InterceptionType type; // Interception type. InterceptorId id; // Interceptor id. base::string16 dll; // Name of dll to intercept. std::string function; // Name of function to intercept. std::string interceptor; // Name of interceptor function. constvoid* interceptor_address; // Interceptor's entry point. };
// 计算config buffer的尺寸,InterceptionManager也需要一个buffer,这个buffer用于 // 承载安装的Interception,然后发给InterceptionAgent // Calculates the size of the required configuration buffer. size_tGetBufferSize()const;
// Rounds up the size of a given buffer, considering alignment (padding). // value is the current size of the buffer, and alignment is specified in // bytes. // 向上对齐 staticinlinesize_tRoundUpToMultiple(size_t value, size_t alignment){ return ((value + alignment - 1) / alignment) * alignment; }
// Sets up a given buffer with all the information that has to be transfered // to the child. // Returns true on success. // // The buffer size should be at least the value returned by GetBufferSize // 部署config buffer boolSetupConfigBuffer(void* buffer, size_t buffer_bytes);
// Fills up the part of the transfer buffer that corresponds to information // about one dll to patch. // data is the first recorded interception for this dll. // Returns true on success. // // On successful return, buffer will be advanced from it's current position // to the point where the next block of configuration data should be written // (the actual interception info), and the current size of the buffer will // decrease to account the space used by this method. // 部署某个被patch的dll的信息到buffer中,这里可以看出buffer中实际上是InterceptionData boolSetupDllInfo(const InterceptionData& data, void** buffer, size_t* buffer_bytes)const;
// Fills up the part of the transfer buffer that corresponds to a single // function to patch. // dll_info points to the dll being updated with the interception stored on // data. The buffer pointer and remaining size are updated by this call. // Returns true on success. // 部署某个单一函数patch的信息到buffer boolSetupInterceptionInfo(const InterceptionData& data, void** buffer, size_t* buffer_bytes, DllPatchInfo* dll_info)const;
// Returns true if this interception is to be performed by the child // as opposed to from the parent. boolIsInterceptionPerformedByChild(const InterceptionData& data)const;
// Allocates a buffer on the child's address space (returned on // remote_buffer), and fills it with the contents of a local buffer. // Returns SBOX_ALL_OK on success. // 这个应该就是跨进程写数据的素质3连 ResultCode CopyDataToChild(constvoid* local_buffer, size_t buffer_bytes, void** remote_buffer)const;
// Performs the cold patch (from the parent) of ntdll. // Returns SBOX_ALL_OK on success. // // This method will insert additional interceptions to launch the interceptor // agent on the child process, if there are additional interceptions to do. ResultCode PatchNtdll(bool hot_patch_needed);
// Peforms the actual interceptions on ntdll. // thunks is the memory to store all the thunks for this dll (on the child), // and dll_data is a local buffer to hold global dll interception info. // Returns SBOX_ALL_OK on success. ResultCode PatchClientFunctions(DllInterceptionData* thunks, size_t thunk_bytes, DllInterceptionData* dll_data);
// The process to intercept. // 看起来一个Manager管理一个target进程 TargetProcess* child_; // Holds all interception info until the call to initialize (perform the // actual patch). // target进程所有待安装的拦截器 std::list<InterceptionData> interceptions_;
// Keep track of patches added by name. bool names_used_;
// true if we are allowed to patch already-patched functions. bool relaxed_;
interceptions_.push_back(function); names_used_ = true; returntrue; } // unload实际上也是一种interception,它的type为固定的INTERCEPTION_UNLOAD_MODULE boolInterceptionManager::AddToUnloadModules(constwchar_t* dll_name){ InterceptionData module_to_unload; module_to_unload.type = INTERCEPTION_UNLOAD_MODULE; module_to_unload.dll = dll_name; // The next two are dummy values that make the structures regular, instead // of having special cases. They should not be used. // 这两个成员对于该对象来说没有实际意义,填充dummy数据 module_to_unload.function = kUnloadDLLDummyFunction; module_to_unload.interceptor_address = reinterpret_cast<void*>(1);
enumInterceptionType { INTERCEPTION_INVALID = 0, INTERCEPTION_SERVICE_CALL, // Trampoline of an NT native call INTERCEPTION_EAT, INTERCEPTION_SIDESTEP, // Preamble patch INTERCEPTION_SMART_SIDESTEP, // Preamble patch but bypass internal calls INTERCEPTION_UNLOAD_MODULE, // Unload the module (don't patch) INTERCEPTION_LAST // Placeholder for last item in the enumeration };
// 迭代interception,interceptions_实际上是std::list<InterceptionData> for (constauto& interception : interceptions_) { // skip interceptions that are performed from the parent // 设计上拦截器分两种,一种由broker来给target执行,另一种由target自己执行 // 前者就不需要传递给target进程了,所以这里做了skip // 那么怎么分类呢?实际上是根据type来判定 if (!IsInterceptionPerformedByChild(interception)) continue;
// 如果本次interception的dll没有出现过,就把该dll的名称插入到dlls // 同一个dll尽管出现多次,也只有一个DllPatchInfo结构 if (!dlls.count(interception.dll)) { // NULL terminate the dll name on the structure size_t dll_name_bytes = (interception.dll.size() + 1) * sizeof(wchar_t);
// include the dll related size // dll_name是DLLPatchInfo的最后一个成员,是个flexible数组,这里是计算出整个结构体真实的长度,且单位要对齐 // 我们mark一下DllPatchInfo结构体 buffer_bytes += RoundUpToMultiple( offsetof(DllPatchInfo, dll_name) + dll_name_bytes, sizeof(size_t)); dlls.insert(interception.dll); }
// we have to NULL terminate the strings on the structure // 被拦截函数的名称尺寸以及拦截函数的尺寸,2表示两个终结符 // 但有个疑问在于我们观察两个重载的Add方法时,发现其中一个并没有设置interceptor // 如果interceptor在这种情况下为空串,那么还好,但Add时并没有设置,所以可能存在隐患 size_t strings_chars = interception.function.size() + interception.interceptor.size() + 2;
// a new FunctionInfo is required per function // FunctionInfo也类似DllPatchInfo,function是最后一个flexible数组成员,这个function是两个字符串,一个function,一个interception size_t record_bytes = offsetof(FunctionInfo, function) + strings_chars; record_bytes = RoundUpToMultiple(record_bytes, sizeof(size_t)); buffer_bytes += record_bytes; }
// SharedMemory也是个类似的结构体,dll_list是最后一个DllPatchInfo flexible数组成员 if (0 != buffer_bytes) // add the part of SharedMemory that we have not counted yet buffer_bytes += offsetof(SharedMemory, dll_list);
// All interceptions: structSharedMemory { int num_intercepted_dlls; void* interceptor_base; DllPatchInfo dll_list[1]; // placeholder for the list of dlls };
// A single dll: structDllPatchInfo { size_t record_bytes; // rounded to sizeof(size_t) bytes size_t offset_to_functions; int num_functions; bool unload_module; wchar_t dll_name[1]; // placeholder for null terminated name // FunctionInfo function_info[] // followed by the functions to intercept };
// Structures for the shared memory that contains patching information // for the InterceptionAgent. // A single interception: structFunctionInfo { size_t record_bytes; // rounded to sizeof(size_t) bytes InterceptionType type; InterceptorId id; constvoid* interceptor_address; char function[1]; // placeholder for null terminated name // char interceptor[] // followed by the interceptor function };
// Basically, walk the list of interceptions moving them to the config buffer, // but keeping together all interceptions that belong to the same dll. // The config buffer is a local buffer, not the one allocated on the child. boolInterceptionManager::SetupConfigBuffer(void* buffer, size_t buffer_bytes){ if (0 == buffer_bytes) returntrue;
//开始了,抽离出每个dll,SetupDllInfo std::list<InterceptionData>::iterator it = interceptions_.begin(); for (; it != interceptions_.end();) { // skip interceptions that are performed from the parent if (!IsInterceptionPerformedByChild(*it)) { ++it; continue; }
// walk the interceptions from this point, saving the ones that are // performed on this dll, and removing the entry from the list. // advance the iterator before removing the element from the list // 找到后面相同dll的interception,一并处理然后移除 std::list<InterceptionData>::iterator rest = it; for (; rest != interceptions_.end();) { if (rest->dll == dll) { if (!SetupInterceptionInfo(*rest, &buffer, &buffer_bytes, dll_info)) returnfalse; if (it == rest) ++it; rest = interceptions_.erase(rest); } else { ++rest; } } dll_info = reinterpret_cast<DllPatchInfo*>(buffer); ++num_dlls; }
// Fills up just the part that depends on the dll, not the info that depends on // the actual interception. boolInterceptionManager::SetupDllInfo(const InterceptionData& data, void** buffer, size_t* buffer_bytes)const{ DCHECK(buffer_bytes); DCHECK(buffer); DCHECK(*buffer);
// the strings have to be zero terminated size_t required = offsetof(DllPatchInfo, dll_name) + (data.dll.size() + 1) * sizeof(wchar_t); required = RoundUpToMultiple(required, sizeof(size_t)); if (*buffer_bytes < required) returnfalse;
// set up the dll info to be what we know about it at this time // 首次处理一个dll时,仅仅填充了dll相关的信息,FunctionInfo还没有拉进来 dll_info->unload_module = (data.type == INTERCEPTION_UNLOAD_MODULE); // 是不是要unload的dll dll_info->record_bytes = required; dll_info->offset_to_functions = required; dll_info->num_functions = 0; data.dll.copy(dll_info->dll_name, data.dll.size()); dll_info->dll_name[data.dll.size()] = L'\0';
// 都要卸载了,还patch个毛,检查一下有没有这种矛盾的情况 if ((dll_info->unload_module) && (data.function != kUnloadDLLDummyFunction)) { // Can't specify a dll for both patch and unload. NOTREACHED(); }
// 常规操作,把InterceptorData的信息全部倒出来,给FunctionInfo FunctionInfo* function = reinterpret_cast<FunctionInfo*>(*buffer);
// the strings at the end of the structure are zero terminated size_t required = offsetof(FunctionInfo, function) + name_bytes + interceptor_bytes + 2; required = RoundUpToMultiple(required, sizeof(size_t)); if (*buffer_bytes < required) returnfalse;
// Allocate memory on the target process without specifying the address // 经典的素质二连:VirtualAllocEx + WriteProcessMemory void* remote_data = ::VirtualAllocEx(child, nullptr, buffer_bytes, MEM_COMMIT, PAGE_READWRITE); if (!remote_data) return SBOX_ERROR_NO_SPACE;
// Only return true if the child should be able to perform this interception. boolInterceptionManager::IsInterceptionPerformedByChild( const InterceptionData& data)const{ // 心智健全? if (INTERCEPTION_INVALID == data.type) returnfalse;
// 系统调用类型的Interception不能由target自己执行,要broker去执行 if (INTERCEPTION_SERVICE_CALL == data.type) returnfalse;
// 心智健全? if (data.type >= INTERCEPTION_LAST) returnfalse;
// ntdll相关的Interception,都只能由broker执行 base::string16 ntdll(kNtdllName); if (ntdll == data.dll) returnfalse; // ntdll has to be intercepted from the parent
ResultCode InterceptionManager::PatchNtdll(bool hot_patch_needed){ // Maybe there is nothing to do // 如果不需要热补丁且interception空空如也,就什么都不用做 if (!hot_patch_needed && interceptions_.empty()) return SBOX_ALL_OK;
// 如果需要热补丁 if (hot_patch_needed) { #if defined(SANDBOX_EXPORTS) // Make sure the functions are not excluded by the linker. #if defined(_WIN64) #pragma comment(linker, "/include:TargetNtMapViewOfSection64") #pragma comment(linker, "/include:TargetNtUnmapViewOfSection64") #else #pragma comment(linker, "/include:_TargetNtMapViewOfSection@44") #pragma comment(linker, "/include:_TargetNtUnmapViewOfSection@12") #endif #endif// defined(SANDBOX_EXPORTS) // 这个宏有点意思,第二个参数的两个InterceptorId是内部使用的前两个成员 ADD_NT_INTERCEPTION(NtMapViewOfSection, MAP_VIEW_OF_SECTION_ID, 44); ADD_NT_INTERCEPTION(NtUnmapViewOfSection, UNMAP_VIEW_OF_SECTION_ID, 12); }
// Reserve a full 64k memory range in the child process. // 在target进程中储备一个64k大小的内存 HANDLE child = child_->Process(); BYTE* thunk_base = reinterpret_cast<BYTE*>(::VirtualAllocEx( child, nullptr, kAllocGranularity, MEM_RESERVE, PAGE_NOACCESS));
// Find an aligned, random location within the reserved range. // 每一个interceptions都占用一个ThunkData,ThunkData实际上是个char[64]包装 // DllInterceptionData是ThunkData flexible数组的头部 size_t thunk_bytes = interceptions_.size() * sizeof(ThunkData) + sizeof(DllInterceptionData); // 在64k内存中找到一个随机的偏移起始,当然偏移必须要合适,即64k-offset的尺寸比thunk_bytes大 size_t thunk_offset = internal::GetGranularAlignedRandomOffset(thunk_bytes);
// Split the base and offset along page boundaries. thunk_base += thunk_offset & ~(kPageSize - 1); thunk_offset &= kPageSize - 1;
// Make an aligned, padded allocation, and move the pointer to our chunk. size_t thunk_bytes_padded = (thunk_bytes + kPageSize - 1) & ~(kPageSize - 1); // 分配padded部分内存空间 thunk_base = reinterpret_cast<BYTE*>( ::VirtualAllocEx(child, thunk_base, thunk_bytes_padded, MEM_COMMIT, PAGE_EXECUTE_READWRITE)); CHECK(thunk_base); // If this fails we'd crash anyway on an invalid access. // 找到存储DllInterceptionData的起始位置 DllInterceptionData* thunks = reinterpret_cast<DllInterceptionData*>(thunk_base + thunk_offset);
// Reset all helpers for a new child. // 清空g_originals全局函数指针数组 memset(g_originals, 0, sizeof(g_originals));
// this should write all the individual thunks to the child's memory // 对target进程的内存空间写入数据,这个函数看起来很关键 ResultCode rc = PatchClientFunctions(thunks, thunk_bytes, &dll_data);
if (rc != SBOX_ALL_OK) return rc;
// and now write the first part of the table to the child's memory // 这里向target进程的内存空间写入了DllInterceptionData头部数据 // 看起来PatchClientFunctions写的是ThunkData[],并更新了dll_data的成员 SIZE_T written; bool ok = !!::WriteProcessMemory(child, thunks, &dll_data, offsetof(DllInterceptionData, thunks), &written);
if (!ok || (offsetof(DllInterceptionData, thunks) != written)) return SBOX_ERROR_CANNOT_WRITE_INTERCEPTION_THUNK;
// Attempt to protect all the thunks, but ignore failure // 对target进程这段空间设置为只读,不允许更改 DWORD old_protection; ::VirtualProtectEx(child, thunks, thunk_bytes, PAGE_EXECUTE_READ, &old_protection);
// This macro simply calls interception_manager.AddToPatchedFunctions with // the given service to intercept (INTERCEPTION_SERVICE_CALL), and assumes that // the interceptor is called "TargetXXX", where XXX is the name of the service. // Note that num_params is the number of bytes to pop out of the stack for // the exported interceptor, following the calling convention of a service call // (WINAPI = with the "C" underscore). #if SANDBOX_EXPORTS #if defined(_WIN64) #define MAKE_SERVICE_NAME(service, params) "Target" #service "64" #else #define MAKE_SERVICE_NAME(service, params) "_Target" #service "@" #params #endif
for (auto interception : interceptions_) { const base::string16 ntdll(kNtdllName); // 必须的是ntdll的系统调用类型拦截器 if (interception.dll != ntdll) return SBOX_ERROR_BAD_PARAMS;
if (INTERCEPTION_SERVICE_CALL != interception.type) return SBOX_ERROR_BAD_PARAMS;
#if defined(SANDBOX_EXPORTS) // We may be trying to patch by function name. if (!interception.interceptor_address) { constchar* address; NTSTATUS ret = thunk->ResolveInterceptor( local_interceptor.get(), interception.interceptor.c_str(), reinterpret_cast<constvoid**>(&address)); if (!NT_SUCCESS(ret)) { ::SetLastError(GetLastErrorFromNtStatus(ret)); return SBOX_ERROR_CANNOT_RESOLVE_INTERCEPTION_THUNK; }
// Translate the local address to an address on the child. interception.interceptor_address = interceptor_base + (address - reinterpret_cast<char*>(local_interceptor.get())); } #endif// defined(SANDBOX_EXPORTS) NTSTATUS ret = thunk->Setup( ntdll_base, interceptor_base, interception.function.c_str(), interception.interceptor.c_str(), interception.interceptor_address, &thunks->thunks[dll_data->num_thunks], // 这里把thunk发在了thunks中,thunks实际上是child的内存空间 thunk_bytes - dll_data->used_bytes, nullptr); if (!NT_SUCCESS(ret)) { ::SetLastError(GetLastErrorFromNtStatus(ret)); return SBOX_ERROR_CANNOT_SETUP_INTERCEPTION_THUNK; }
// Dummy single thunk: structThunkData { char data[kMaxThunkDataBytes]; };
// In-memory representation of the interceptions for a given dll: structDllInterceptionData { size_t data_bytes; size_t used_bytes; void* base; int num_thunks; #if defined(_WIN64) int dummy; // Improve alignment. #endif ThunkData thunks[1]; };
// of setting up the desired interceptions or indicating what module needs to // be unloaded. // target进程上部署具体的拦截器,broker的manager把interceptions发了过来 // // The exposed API consists of three methods: GetInterceptionAgent to retrieve // the single class instance, OnDllLoad and OnDllUnload to process a dll being // loaded and unloaded respectively. // // This class assumes that it will get called for every dll being loaded, // starting with kernel32, so the singleton will be instantiated from within the // loader lock. classInterceptionAgent { public: // Returns the single InterceptionAgent object for this process. // InterceptionAgent是单例模式 static InterceptionAgent* GetInterceptionAgent();
// This method should be invoked whenever a new dll is loaded to perform the // required patches. If the return value is false, this dll should not be // allowed to load. // // full_path is the (optional) full name of the module being loaded and name // is the internal module name. If full_path is provided, it will be used // before the internal name to determine if we care about this dll. boolOnDllLoad(const UNICODE_STRING* full_path, const UNICODE_STRING* name, void* base_address);
// Performs cleanup when a dll is unloaded. voidOnDllUnload(void* base_address);
private: ~InterceptionAgent() {} // 限定到static成员使用
// Performs initialization of the singleton. boolInit(SharedMemory* shared_memory);
// Returns true if we are interested on this dll. dll_info is an entry of the // list of intercepted dlls. boolDllMatch(const UNICODE_STRING* full_path, const UNICODE_STRING* name, const DllPatchInfo* dll_info);
// Performs the patching of the dll loaded at base_address. // The patches to perform are described on dll_info, and thunks is the thunk // storage for the whole dll. // Returns true on success. boolPatchDll(const DllPatchInfo* dll_info, DllInterceptionData* thunks);
// 这里又出现了一个ResolverThunk // Returns a resolver for a given interception type. ResolverThunk* GetResolver(InterceptionType type);
// 这个是SharedMemory结构 // 里面描述了有哪些dll,每个dll的哪些函数被hook了 // Shared memory containing the list of functions to intercept. SharedMemory* interceptions_;
// Array of thunk data buffers for the intercepted dlls. This object singleton // is allocated with a placement new with enough space to hold the complete // array of pointers, not just the first element. // 这个是DllInterceptionData flexible数组结构,每个dll对应一个成员,这里面承载的是thunk数据 DllInterceptionData* dlls_[1];
// Memory buffer mapped from the parent, with the list of interceptions. // 这个已经认识了,存储数据的内存空间由broker开辟,g_interceptions会指向那段空间 SANDBOX_INTERCEPT SharedMemory* g_interceptions = nullptr;
InterceptionAgent* InterceptionAgent::GetInterceptionAgent(){ static InterceptionAgent* s_singleton = nullptr; if (!s_singleton) { if (!g_interceptions) // broker得把信息发过来先 returnnullptr;
// TODO(rvargas): We have to deal with prebinded dlls. I see two options: change // the timestamp of the patched dll, or modify the info on the prebinded dll. // the first approach messes matching of debug symbols, the second one is more // complicated. boolInterceptionAgent::PatchDll(const DllPatchInfo* dll_info, DllInterceptionData* thunks){ DCHECK_NT(thunks); DCHECK_NT(dll_info);
// This method is called from within the loader lock ResolverThunk* InterceptionAgent::GetResolver(InterceptionType type){ // 这几个都是ResolverThunk的派生类,根据名称可以发现和type息息相关 // 看起来此前的推断是正确的 static EatResolverThunk* eat_resolver = nullptr; static SidestepResolverThunk* sidestep_resolver = nullptr; static SmartSidestepResolverThunk* smart_sidestep_resolver = nullptr;
// static成员,在第一次进入时new出单例 if (!eat_resolver) eat_resolver = new (NT_ALLOC) EatResolverThunk;
#if !defined(_WIN64) // Sidestep is not supported for x64. // sidestep和smart_sidestep不能在x64上使用 if (!sidestep_resolver) sidestep_resolver = new (NT_ALLOC) SidestepResolverThunk;
if (!smart_sidestep_resolver) smart_sidestep_resolver = new (NT_ALLOC) SmartSidestepResolverThunk; #endif