|
@@ -26,6 +26,7 @@
|
|
|
#include "platform.h"
|
|
|
#include "darray.h"
|
|
|
#include "dstr.h"
|
|
|
+#include "obsconfig.h"
|
|
|
#include "util_uint64.h"
|
|
|
#include "windows/win-registry.h"
|
|
|
#include "windows/win-version.h"
|
|
@@ -136,71 +137,83 @@ void os_dlclose(void *module)
|
|
|
FreeLibrary(module);
|
|
|
}
|
|
|
|
|
|
-bool os_is_obs_plugin(const char *path)
|
|
|
+#if OBS_QT_VERSION == 6
|
|
|
+static bool has_qt5_import(VOID *base, PIMAGE_NT_HEADERS nt_headers)
|
|
|
{
|
|
|
- struct dstr dll_name;
|
|
|
- wchar_t *wpath;
|
|
|
+ __try {
|
|
|
+ PIMAGE_DATA_DIRECTORY data_dir;
|
|
|
+ data_dir =
|
|
|
+ &nt_headers->OptionalHeader
|
|
|
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
|
|
|
|
|
- HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
|
- HANDLE hFileMapping = NULL;
|
|
|
- VOID *base = NULL;
|
|
|
+ if (data_dir->Size == 0)
|
|
|
+ return false;
|
|
|
|
|
|
- PIMAGE_DOS_HEADER dos_header;
|
|
|
- PIMAGE_NT_HEADERS nt_headers;
|
|
|
- PIMAGE_SECTION_HEADER section, last_section;
|
|
|
+ PIMAGE_SECTION_HEADER section, last_section;
|
|
|
+ section = IMAGE_FIRST_SECTION(nt_headers);
|
|
|
+ last_section = section;
|
|
|
|
|
|
- bool ret = false;
|
|
|
+ /* find the section that contains the export directory */
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < nt_headers->FileHeader.NumberOfSections; i++) {
|
|
|
+ if (section->VirtualAddress <=
|
|
|
+ data_dir->VirtualAddress) {
|
|
|
+ last_section = section;
|
|
|
+ section++;
|
|
|
+ continue;
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (!path)
|
|
|
- return false;
|
|
|
+ /* double check in case we exited early */
|
|
|
+ if (last_section->VirtualAddress > data_dir->VirtualAddress ||
|
|
|
+ section->VirtualAddress <= data_dir->VirtualAddress)
|
|
|
+ return false;
|
|
|
|
|
|
- dstr_init_copy(&dll_name, path);
|
|
|
- dstr_replace(&dll_name, "\\", "/");
|
|
|
- if (!dstr_find(&dll_name, ".dll"))
|
|
|
- dstr_cat(&dll_name, ".dll");
|
|
|
- os_utf8_to_wcs_ptr(dll_name.array, 0, &wpath);
|
|
|
+ section = last_section;
|
|
|
|
|
|
- dstr_free(&dll_name);
|
|
|
+ /* get a pointer to the import directory */
|
|
|
+ PIMAGE_IMPORT_DESCRIPTOR import;
|
|
|
+ import = (PIMAGE_IMPORT_DESCRIPTOR)((byte *)base +
|
|
|
+ data_dir->VirtualAddress -
|
|
|
+ section->VirtualAddress +
|
|
|
+ section->PointerToRawData);
|
|
|
|
|
|
- hFile = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
|
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
|
|
+ while (import->Name != 0) {
|
|
|
+ char *name = (char *)((byte *)base + import->Name -
|
|
|
+ section->VirtualAddress +
|
|
|
+ section->PointerToRawData);
|
|
|
|
|
|
- bfree(wpath);
|
|
|
+ /* qt5? bingo, reject this library */
|
|
|
+ if (astrcmpi_n(name, "qt5", 3) == 0) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- if (hFile == INVALID_HANDLE_VALUE)
|
|
|
- goto cleanup;
|
|
|
+ import++;
|
|
|
+ }
|
|
|
|
|
|
- hFileMapping =
|
|
|
- CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
- if (hFileMapping == NULL)
|
|
|
- goto cleanup;
|
|
|
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
+ /* we failed somehow, for compatibility assume no qt5 import */
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- base = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
|
|
|
- if (!base)
|
|
|
- goto cleanup;
|
|
|
+ return false;
|
|
|
+}
|
|
|
+#endif
|
|
|
|
|
|
- /* all mapped file i/o must be prepared to handle exceptions */
|
|
|
+static bool has_obs_export(VOID *base, PIMAGE_NT_HEADERS nt_headers)
|
|
|
+{
|
|
|
__try {
|
|
|
-
|
|
|
- dos_header = (PIMAGE_DOS_HEADER)base;
|
|
|
-
|
|
|
- if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
|
|
|
- goto cleanup;
|
|
|
-
|
|
|
- nt_headers = (PIMAGE_NT_HEADERS)((byte *)dos_header +
|
|
|
- dos_header->e_lfanew);
|
|
|
-
|
|
|
- if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
|
|
|
- goto cleanup;
|
|
|
-
|
|
|
PIMAGE_DATA_DIRECTORY data_dir;
|
|
|
data_dir =
|
|
|
&nt_headers->OptionalHeader
|
|
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
|
|
|
|
|
if (data_dir->Size == 0)
|
|
|
- goto cleanup;
|
|
|
+ return false;
|
|
|
|
|
|
+ PIMAGE_SECTION_HEADER section, last_section;
|
|
|
section = IMAGE_FIRST_SECTION(nt_headers);
|
|
|
last_section = section;
|
|
|
|
|
@@ -220,7 +233,7 @@ bool os_is_obs_plugin(const char *path)
|
|
|
/* double check in case we exited early */
|
|
|
if (last_section->VirtualAddress > data_dir->VirtualAddress ||
|
|
|
section->VirtualAddress <= data_dir->VirtualAddress)
|
|
|
- goto cleanup;
|
|
|
+ return false;
|
|
|
|
|
|
section = last_section;
|
|
|
|
|
@@ -232,7 +245,7 @@ bool os_is_obs_plugin(const char *path)
|
|
|
section->PointerToRawData);
|
|
|
|
|
|
if (export->NumberOfNames == 0)
|
|
|
- goto cleanup;
|
|
|
+ return false;
|
|
|
|
|
|
/* get a pointer to the export directory names */
|
|
|
DWORD *names_ptr;
|
|
@@ -250,15 +263,90 @@ bool os_is_obs_plugin(const char *path)
|
|
|
section->PointerToRawData;
|
|
|
|
|
|
if (!strcmp(name, "obs_module_load")) {
|
|
|
- ret = true;
|
|
|
- goto cleanup;
|
|
|
+ return true;
|
|
|
}
|
|
|
}
|
|
|
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
+ /* we failed somehow, for compatibility let's assume it
|
|
|
+ * was a valid plugin and let the loader deal with it */
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void get_plugin_info(const char *path, bool *is_obs_plugin, bool *can_load)
|
|
|
+{
|
|
|
+ struct dstr dll_name;
|
|
|
+ wchar_t *wpath;
|
|
|
+
|
|
|
+ HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
|
+ HANDLE hFileMapping = NULL;
|
|
|
+ VOID *base = NULL;
|
|
|
+
|
|
|
+ PIMAGE_DOS_HEADER dos_header;
|
|
|
+ PIMAGE_NT_HEADERS nt_headers;
|
|
|
+
|
|
|
+ *is_obs_plugin = false;
|
|
|
+ *can_load = false;
|
|
|
+
|
|
|
+ if (!path)
|
|
|
+ return;
|
|
|
+
|
|
|
+ dstr_init_copy(&dll_name, path);
|
|
|
+ dstr_replace(&dll_name, "\\", "/");
|
|
|
+ if (!dstr_find(&dll_name, ".dll"))
|
|
|
+ dstr_cat(&dll_name, ".dll");
|
|
|
+ os_utf8_to_wcs_ptr(dll_name.array, 0, &wpath);
|
|
|
+
|
|
|
+ dstr_free(&dll_name);
|
|
|
+
|
|
|
+ hFile = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
|
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
|
|
+
|
|
|
+ bfree(wpath);
|
|
|
+
|
|
|
+ if (hFile == INVALID_HANDLE_VALUE)
|
|
|
+ goto cleanup;
|
|
|
+
|
|
|
+ hFileMapping =
|
|
|
+ CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
+ if (hFileMapping == NULL)
|
|
|
+ goto cleanup;
|
|
|
+
|
|
|
+ base = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
|
|
|
+ if (!base)
|
|
|
+ goto cleanup;
|
|
|
+
|
|
|
+ /* all mapped file i/o must be prepared to handle exceptions */
|
|
|
+ __try {
|
|
|
+
|
|
|
+ dos_header = (PIMAGE_DOS_HEADER)base;
|
|
|
+
|
|
|
+ if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
|
|
|
+ goto cleanup;
|
|
|
+
|
|
|
+ nt_headers = (PIMAGE_NT_HEADERS)((byte *)dos_header +
|
|
|
+ dos_header->e_lfanew);
|
|
|
+
|
|
|
+ if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
|
|
|
+ goto cleanup;
|
|
|
+
|
|
|
+ *is_obs_plugin = has_obs_export(base, nt_headers);
|
|
|
+
|
|
|
+#if OBS_QT_VERSION == 6
|
|
|
+ if (*is_obs_plugin) {
|
|
|
+ *can_load = !has_qt5_import(base, nt_headers);
|
|
|
+ }
|
|
|
+#else
|
|
|
+ *can_load = true;
|
|
|
+#endif
|
|
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
/* we failed somehow, for compatibility let's assume it
|
|
|
* was a valid plugin and let the loader deal with it */
|
|
|
- ret = true;
|
|
|
+ *is_obs_plugin = true;
|
|
|
+ *can_load = true;
|
|
|
goto cleanup;
|
|
|
}
|
|
|
|
|
@@ -271,8 +359,16 @@ cleanup:
|
|
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
|
CloseHandle(hFile);
|
|
|
+}
|
|
|
|
|
|
- return ret;
|
|
|
+bool os_is_obs_plugin(const char *path)
|
|
|
+{
|
|
|
+ bool is_obs_plugin;
|
|
|
+ bool can_load;
|
|
|
+
|
|
|
+ get_plugin_info(path, &is_obs_plugin, &can_load);
|
|
|
+
|
|
|
+ return is_obs_plugin && can_load;
|
|
|
}
|
|
|
|
|
|
union time_data {
|