1 : // Copyright 2015 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include <windows.h>
16 :
17 : #include "base/at_exit.h"
18 : #include "base/command_line.h"
19 : #include "base/logging.h"
20 : #include "syzygy/agent/asan/hot_patching_asan_runtime.h"
21 : #include "syzygy/agent/common/agent.h"
22 : #include "syzygy/common/logging.h"
23 :
24 : // This instrumentation hook is used for calls to a DLL's entry point.
25 : //
26 : // Note that the calling convention to this function is non-conventional.
27 : // This function is invoked by a generated stub that does:
28 : //
29 : // push <original dllmain>
30 : // jmp _indirect_penter_dllmain
31 : //
32 : // This function will pass the <original dllmain> pointer and a frame to its
33 : // parameters to HotPatchingAsanRuntime::DllMainEntryHook, and then on exit,
34 : // will arrange for execution to jump to <original dllmain>.
35 m : extern "C" void __declspec(naked) _cdecl _indirect_penter_dllmain() {
36 m : __asm {
37 : // Stash volatile registers.
38 m : push eax
39 m : push ecx
40 m : push edx
41 m : pushfd
42 :
43 : // Retrieve the address pushed by our caller.
44 m : mov eax, DWORD PTR[esp + 0x10]
45 m : push eax
46 :
47 : // Calculate the position of the return address on stack, and
48 : // push it. This becomes the EntryFrame argument.
49 m : lea eax, DWORD PTR[esp + 0x18]
50 m : push eax
51 m : call agent::asan::HotPatchingAsanRuntime::DllMainEntryHook
52 :
53 : // Restore volatile registers.
54 m : popfd
55 m : pop edx
56 m : pop ecx
57 m : pop eax
58 :
59 : // Return to the address pushed by our caller.
60 m : ret
61 m : }
62 m : }
63 :
64 m : namespace {
65 :
66 : // Our AtExit manager required by base.
67 m : base::AtExitManager* at_exit = nullptr;
68 :
69 m : void SetUpAtExitManager() {
70 m : DCHECK_EQ(static_cast<base::AtExitManager*>(nullptr), at_exit);
71 m : at_exit = new base::AtExitManager();
72 m : CHECK_NE(static_cast<base::AtExitManager*>(nullptr), at_exit);
73 m : }
74 :
75 m : void TearDownAtExitManager() {
76 m : DCHECK_NE(static_cast<base::AtExitManager*>(nullptr), at_exit);
77 m : delete at_exit;
78 m : at_exit = nullptr;
79 m : }
80 :
81 m : } // namespace
82 :
83 m : extern "C" {
84 :
85 m : BOOL WINAPI DllMain(HMODULE instance, DWORD reason, LPVOID reserved) {
86 m : agent::common::InitializeCrt();
87 :
88 m : switch (reason) {
89 m : case DLL_PROCESS_ATTACH: {
90 : // Create the At-Exit manager.
91 m : SetUpAtExitManager();
92 :
93 : // Disable logging. In the case of Chrome this is running in a sandboxed
94 : // process where logging to file doesn't help us any. In other cases the
95 : // log output will still go to console.
96 m : base::CommandLine::Init(0, NULL);
97 m : common::InitLoggingForDll(L"syzyasan_hp");
98 :
99 : // Set up the hot patching Asan runtime.
100 m : agent::asan::HotPatchingAsanRuntime::GetInstance()->SetUp();
101 :
102 m : break;
103 m : }
104 :
105 m : case DLL_THREAD_ATTACH:
106 : // Nothing to do here.
107 m : break;
108 :
109 m : case DLL_THREAD_DETACH:
110 : // Nothing to do here.
111 m : break;
112 :
113 m : case DLL_PROCESS_DETACH: {
114 m : TearDownAtExitManager();
115 m : break;
116 m : }
117 :
118 m : default:
119 m : NOTREACHED();
120 m : break;
121 m : }
122 :
123 m : return TRUE;
124 m : }
125 :
126 m : } // extern "C"
|