Skip to content

Commit ef92d07

Browse files
committed
[Issue JLospinoso#9] Search for the ROP gadget in "mshtml.dll" at run-time instead
of using hard coded offsets - Gargoyle now loads the "mshtml.dll" system DLL into memory and searches the executable portions of its address space to find a suitable ROP gadget. As a result, Gargoyle is now immune to Microsoft updating "mshtml.dll", as long as the DLL is not changed at some point to eliminate the ROP gadget.
1 parent 6db1473 commit ef92d07

File tree

2 files changed

+60
-98
lines changed

2 files changed

+60
-98
lines changed

Gargoyle.vcxproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
<Link>
7474
<SubSystem>Console</SubSystem>
7575
<GenerateDebugInformation>true</GenerateDebugInformation>
76-
<AdditionalDependencies>version.lib;%(AdditionalDependencies)</AdditionalDependencies>
76+
<AdditionalDependencies>DbgHelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
7777
</Link>
7878
</ItemDefinitionGroup>
7979
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -91,7 +91,7 @@
9191
<EnableCOMDATFolding>true</EnableCOMDATFolding>
9292
<OptimizeReferences>true</OptimizeReferences>
9393
<GenerateDebugInformation>true</GenerateDebugInformation>
94-
<AdditionalDependencies>version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
94+
<AdditionalDependencies>DbgHelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
9595
</Link>
9696
</ItemDefinitionGroup>
9797
<ItemGroup>

main.cpp

+58-96
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
#include <vector>
2-
#include <tuple>
1+
#include <algorithm>
32
#include <fstream>
4-
#include "Windows.h"
5-
#include <psapi.h>
3+
#include <tuple>
64
#include <vector>
75

6+
#include <Windows.h>
7+
#include <DbgHelp.h>
8+
#include <winnt.h>
9+
810
using namespace std;
911

1012
namespace {
@@ -13,26 +15,9 @@ namespace {
1315
constexpr DWORD invocation_interval_ms = 15 * 1000;
1416
constexpr size_t stack_size = 0x10000;
1517

16-
struct VersionToOffset {
17-
WORD file_version[4];
18-
uint32_t relative_offset;
19-
};
20-
21-
/*
22-
* See https://changewindows.org/ for a detailed Windows 10 release history,
23-
* including updates to milestone releases. A new build of the "mshtml.dll"
24-
* file has not been included with every update.
25-
*/
26-
27-
vector<VersionToOffset> mshtml_gadget_offset_map = {
28-
// Windows 10 Creators Update (Build v10.0.15063.138 as of Apr 11, 2017)
29-
{ 11, 0, 15063, 138, 0x00585068 },
30-
// Windows 10 Creators Update (Build v10.0.15063.0 as of Mar 20, 2017)
31-
{ 11, 0, 15063, 0, 0x00585098 },
32-
// Windows 10 Anniversary Update (Build v10.0.14393.953 as of Mar 14, 2017)
33-
{ 11, 0, 14393, 953, 0x003CBD4D },
34-
// The default ROP gadget offset (for Windows v8.1?)
35-
{ 0, 0, 0, 0, 0x006D55DD }
18+
vector<vector<uint8_t>> rop_gadget_candidates = {
19+
{ 0x59, 0x5C, 0xC3 }, // pop ecx; pop esp; ret
20+
{ 0x58, 0x5C, 0xC3 } // pop eax; pop esp; ret
3621
};
3722

3823
struct SetupConfiguration {
@@ -78,9 +63,8 @@ Workspace& allocate_workspace() {
7863
}
7964

8065
MyTuple allocate_pic(const string& filename) {
81-
8266
fstream file_stream{ filename, fstream::in | fstream::ate | fstream::binary };
83-
if (!file_stream) throw runtime_error("[-] Couldn't open " + filename);
67+
if (!file_stream) throw runtime_error("[-] Couldn't open \"" + filename + "\".");
8468
auto pic_size = static_cast<size_t>(file_stream.tellg());
8569
file_stream.seekg(0, fstream::beg);
8670
auto pic = VirtualAllocEx(GetCurrentProcess(), nullptr, pic_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
@@ -93,92 +77,70 @@ MyTuple allocate_pic(const string& filename) {
9377
return MyTuple(pic, pic_size);
9478
}
9579

96-
uint32_t get_mshtml_gadget_relative_offset(const char *mshtml_filename) {
97-
DWORD version_handle;
98-
auto version_info_size = GetFileVersionInfoSizeA(mshtml_filename, &version_handle);
99-
if (version_info_size == 0) throw runtime_error("[-] Couldn't GetFileVersionInfoSize: " + GetLastError());
100-
101-
vector<char> version_data(version_info_size);
102-
auto result = GetFileVersionInfoA(mshtml_filename, version_handle, version_info_size, &version_data[0]);
103-
if (!result) {
104-
throw runtime_error("[-] Couldn't GetFileVersionInfo: " + GetLastError());
105-
}
106-
107-
LPBYTE version_info_buffer;
108-
UINT version_info_buffer_size;
109-
result = VerQueryValueA(&version_data[0], "\\", reinterpret_cast<VOID FAR* FAR*>(&version_info_buffer), &version_info_buffer_size);
110-
if (!result) {
111-
throw runtime_error("[-] Couldn't VerQueryValue: " + GetLastError());
112-
}
113-
114-
auto *version_info = reinterpret_cast<VS_FIXEDFILEINFO *>(version_info_buffer);
115-
WORD unpacked_file_version_words[4] = {
116-
(version_info->dwFileVersionMS >> 16) & 0xffff,
117-
(version_info->dwFileVersionMS >> 0) & 0xffff,
118-
(version_info->dwFileVersionLS >> 16) & 0xffff,
119-
(version_info->dwFileVersionLS >> 0) & 0xffff };
120-
auto unpacked_file_version = *reinterpret_cast<DWORDLONG *>(unpacked_file_version_words);
121-
122-
printf("[ ] Found %s version %d.%d.%d.%d.\n",
123-
mshtml_filename,
124-
unpacked_file_version_words[0],
125-
unpacked_file_version_words[1],
126-
unpacked_file_version_words[2],
127-
unpacked_file_version_words[3]);
128-
129-
uint32_t relative_offset = 0;
130-
auto using_default = false;
131-
auto entry_num = 0;
132-
while (relative_offset == 0) {
133-
auto* version_entry = &mshtml_gadget_offset_map[entry_num];
134-
if (*reinterpret_cast<DWORDLONG *>(version_entry->file_version) == unpacked_file_version
135-
|| *reinterpret_cast<DWORDLONG *>(version_entry->file_version) == 0)
136-
relative_offset = version_entry->relative_offset;
137-
using_default = *reinterpret_cast<DWORDLONG *>(version_entry->file_version) == 0;
138-
++entry_num;
139-
}
80+
void* get_system_dll_gadget(const string& system_dll_filename) {
81+
printf("[ ] Loading \"%s\" system DLL.\n", system_dll_filename.c_str());
82+
auto dll_base = reinterpret_cast<uint8_t*>(LoadLibraryA(system_dll_filename.c_str()));
83+
if (!dll_base) throw runtime_error("[-] Couldn't LoadLibrary: " + GetLastError());
84+
85+
printf("[+] Loaded \"%s\" at 0x%p.\n", system_dll_filename.c_str(), dll_base);
86+
87+
auto pe_header = ImageNtHeader(dll_base);
88+
if (!pe_header) throw runtime_error("[-] Couldn't ImageNtHeader: " + GetLastError());
89+
90+
auto filtered_section_headers = vector<PIMAGE_SECTION_HEADER>();
91+
auto section_header = reinterpret_cast<PIMAGE_SECTION_HEADER>(pe_header + 1);
92+
for (int i = 0; i < pe_header->FileHeader.NumberOfSections; ++i)
93+
{
94+
if (section_header->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
95+
filtered_section_headers.push_back(section_header);
96+
printf("[ ] Found executable section \"%s\" at 0x%p.\n", section_header->Name, dll_base + section_header->VirtualAddress);
97+
}
98+
section_header++;
99+
};
140100

141-
if (using_default) {
142-
printf("[*] WARNING: Unrecognized version, so using default relative offset.\n");
101+
for (auto section_header : filtered_section_headers)
102+
{
103+
for (auto rop_gadget : rop_gadget_candidates)
104+
{
105+
auto section_base = dll_base + section_header->VirtualAddress;
106+
vector<uint8_t> section_content(section_base, section_base + section_header->Misc.VirtualSize);
107+
auto search_result = search(begin(section_content), end(section_content), begin(rop_gadget), end(rop_gadget));
108+
if (search_result == end(section_content))
109+
continue;
110+
111+
auto rop_gadget_offset = section_base + (search_result - begin(section_content));
112+
printf("[+] Found ROP gadget in section \"%s\" at 0x%p.\n", section_header->Name, rop_gadget_offset);
113+
return rop_gadget_offset;
114+
}
143115
}
144-
printf("[ ] %s ROP gadget is at relative offset 0x%p.\n", mshtml_filename, reinterpret_cast<void *>(relative_offset));
145116

146-
return relative_offset;
117+
printf("[-] Didn't find ROP gadget in \"%s\".\n", system_dll_filename.c_str());
118+
return 0;
147119
}
148120

149-
void* get_mshtml_gadget() {
150-
auto mshtml_filename = "mshtml.dll";
151-
printf("[ ] Loading %s.\n", mshtml_filename);
152-
auto mshtml_gadget_offset = get_mshtml_gadget_relative_offset(mshtml_filename);
153-
auto mshtml_base = reinterpret_cast<uint8_t*>(LoadLibraryA(mshtml_filename));
154-
if (!mshtml_base) throw runtime_error("[-] Couldn't LoadLibrary: " + GetLastError());
155-
156-
printf("[+] Loaded %s into memory at 0x%p.\n", mshtml_filename, mshtml_base);
157-
return mshtml_base + mshtml_gadget_offset;
158-
}
159-
160-
void* get_gadget(bool use_mshtml, const string& gadget_pic_path) {
121+
void* get_gadget(bool use_system_dll, const string& gadget_system_dll_filename, const string& gadget_pic_path) {
161122
void* memory;
162-
if (use_mshtml) {
163-
memory = get_mshtml_gadget();
164-
} else {
165-
printf("[ ] Allocating memory for %s.\n", gadget_pic_path.c_str());
123+
if (use_system_dll) {
124+
memory = get_system_dll_gadget(gadget_system_dll_filename);
125+
}
126+
if (!use_system_dll || !memory) {
127+
printf("[ ] Allocating executable memory for \"%s\".\n", gadget_pic_path.c_str());
166128
size_t size;
167129
tie(memory, size) = allocate_pic(gadget_pic_path);
168-
printf("[ ] Allocated %u bytes for gadget PIC.\n", size);
130+
printf("[+] Allocated %u bytes for gadget PIC.\n", size);
169131
}
170132
return memory;
171133
}
172134

173-
void launch(const string& setup_pic_path, const string& gadget_pic_path) {
174-
printf("[ ] Allocating executable memory for %s.\n", setup_pic_path.c_str());
135+
void launch(const string& setup_pic_path, const string& gadget_system_dll_filename, const string& gadget_pic_path) {
136+
printf("[ ] Allocating executable memory for \"%s\".\n", setup_pic_path.c_str());
175137
void* setup_memory; size_t setup_size;
176138
tie(setup_memory, setup_size) = allocate_pic(setup_pic_path);
177139
printf("[+] Allocated %d bytes for PIC.\n", setup_size);
178140

179-
auto use_mshtml{ true };
141+
auto use_system_dll{ true };
180142
printf("[ ] Configuring ROP gadget.\n");
181-
auto gadget_memory = get_gadget(use_mshtml, gadget_pic_path);
143+
auto gadget_memory = get_gadget(use_system_dll, gadget_system_dll_filename, gadget_pic_path);
182144
printf("[+] ROP gadget configured.\n");
183145

184146
printf("[ ] Allocating read/write memory for config, stack, and trampoline.\n");
@@ -225,7 +187,7 @@ void launch(const string& setup_pic_path, const string& gadget_pic_path) {
225187

226188
int main() {
227189
try {
228-
launch("setup.pic", "gadget.pic");
190+
launch("setup.pic", "mshtml.dll", "gadget.pic");
229191
} catch (exception& e) {
230192
printf("%s\n", e.what());
231193
}

0 commit comments

Comments
 (0)