diff --git a/ep_extra/README.md b/ep_extra/README.md new file mode 100644 index 000000000..580ef750e --- /dev/null +++ b/ep_extra/README.md @@ -0,0 +1,5 @@ +# ExplorerPatcher Custom Libraries Chainloader + +ExplorerPatcher has a simple, built-in mechanism that allows users to load their own DLL into `explorer.exe` right after ExplorerPatcher finishes initializing its hooks. Interested users hould place a DLL called `ep_extra.dll` in `C:\Windows`. When ExplorerPatcher finishes its setup, it loads the `ep_extra.dll` library and calls the `ep_extra_EntryPoint` function. Although this is very useful so that users can load their custom code, it is quite limited at the moment, as it loads just one DLL. + +This project is a solution to this issue. A chainloader is implemented here, that looks for other modules matching the `ep_extra_*.dll` pattern in `C:\Windows` as well, and loads them one after the other. diff --git a/ep_extra/ep_extra.rc b/ep_extra/ep_extra.rc new file mode 100644 index 000000000..0dca6b07c --- /dev/null +++ b/ep_extra/ep_extra.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "VALINET Solutions SRL" + VALUE "FileDescription", "ExplorerPatcher Custom Libraries Chainloader" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "ep_extra.dll" + VALUE "LegalCopyright", "Copyright (C) 2006-2022 VALINET Solutions SRL. All rights reserved." + VALUE "OriginalFilename", "ep_extra.dll" + VALUE "ProductName", "ExplorerPatcher" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ep_extra/ep_extra.vcxproj b/ep_extra/ep_extra.vcxproj new file mode 100644 index 000000000..0e333464e --- /dev/null +++ b/ep_extra/ep_extra.vcxproj @@ -0,0 +1,179 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {93fa47cc-7753-4f86-b583-69048f51c5ab} + epextra + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(Configuration) + + + false + $(SolutionDir)\build\$(Configuration) + + + true + $(SolutionDir)\build\$(Configuration) + + + false + $(SolutionDir)\build\$(Configuration) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDebug + + + Console + true + + + /EXPORT:ep_extra_EntryPoint %(AdditionalOptions) + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + true + true + + + /EXPORT:ep_extra_EntryPoint %(AdditionalOptions) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDebug + + + Console + true + + + /EXPORT:ep_extra_EntryPoint %(AdditionalOptions) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + true + true + + + %(AdditionalOptions) + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ep_extra/ep_extra.vcxproj.filters b/ep_extra/ep_extra.vcxproj.filters new file mode 100644 index 000000000..e30d842f1 --- /dev/null +++ b/ep_extra/ep_extra.vcxproj.filters @@ -0,0 +1,37 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Source Files + + + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/ep_extra/main.asm b/ep_extra/main.asm new file mode 100644 index 000000000..e57969ab7 --- /dev/null +++ b/ep_extra/main.asm @@ -0,0 +1,18 @@ +EXTERN worker : PROC + +.CODE + +ep_extra_EntryPoint PROC EXPORT + PUSH RBP + MOV RBP, RSP + SUB RSP, 30H + CALL worker + CMP RAX, 0 + JE finish + JMP RAX +finish: + LEAVE + RET +ep_extra_EntryPoint ENDP + +END \ No newline at end of file diff --git a/ep_extra/resource.h b/ep_extra/resource.h new file mode 100644 index 000000000..bc8b44eac --- /dev/null +++ b/ep_extra/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ep_extra.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/ep_extra/worker.c b/ep_extra/worker.c new file mode 100644 index 000000000..8f0b97fe1 --- /dev/null +++ b/ep_extra/worker.c @@ -0,0 +1,82 @@ +#include +#include +#pragma comment(lib, "Shlwapi.lib") +#include + +HMODULE hModule = NULL; +HANDLE sigFinish = NULL; +void* pFinishProc = NULL; + +void done() { + WaitForSingleObject(sigFinish, INFINITE); + FreeLibraryAndExitThread(hModule, 0); +} + +void* worker() { + wchar_t pattern[MAX_PATH]; + GetWindowsDirectoryW(pattern, MAX_PATH); + wcscat_s(pattern, MAX_PATH, L"\\ep_extra_*.dll"); + + WIN32_FIND_DATA data; + HANDLE hFind = FindFirstFileW(pattern, &data); + if (hFind != INVALID_HANDLE_VALUE) { + do { + wprintf(L">> Found ep_extra library: \"%s\"\n", data.cFileName); + GetWindowsDirectoryW(pattern, MAX_PATH); + wcscat_s(pattern, MAX_PATH, L"\\"); + wcscat_s(pattern, MAX_PATH, data.cFileName); + HMODULE hLib = LoadLibraryW(pattern); + if (hLib) { + FARPROC proc = (FARPROC)(GetProcAddress(hLib, "setup")); + if (proc) { + if (!proc()) FreeLibrary(hLib); + } + else FreeLibrary(hLib); + } + } while (FindNextFileW(hFind, &data)); + FindClose(hFind); + } + + sigFinish = CreateEventW(NULL, FALSE, FALSE, NULL); + if (sigFinish) { + BYTE payload[] = { + 0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rcx, sigFinish + 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, SetEvent + 0xFF, 0xD0, // call SetEvent + 0xC9, // leave + 0xC3 // ret + }; + *(INT64*)(payload + 2) = sigFinish; + *(INT64*)(payload + 12) = SetEvent; + + pFinishProc = VirtualAlloc(NULL, sizeof(payload), MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (pFinishProc) { + memcpy(pFinishProc, payload, sizeof(payload)); + SHCreateThread(done, 0, CTF_NOADDREFLIB, NULL); + return pFinishProc; + } + } + return NULL; +} + +BOOL WINAPI DllMain( + _In_ HINSTANCE hinstDLL, + _In_ DWORD fdwReason, + _In_ LPVOID lpvReserved +) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + hModule = hinstDLL; + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +}