diff --git a/GeDoSaTo.sln b/GeDoSaTo.sln
index 9f146ff..bdf3422 100644
--- a/GeDoSaTo.sln
+++ b/GeDoSaTo.sln
@@ -1,7 +1,11 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 11
+# Visual Studio 14
+VisualStudioVersion = 14.0.23107.0
+MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GeDoSaTo", "GeDoSaTo.vcxproj", "{E004A114-54E0-B15C-BDA5-46681084E257}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gedosato_shim", "gedosato_shim\gedosato_shim.vcxproj", "{08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -18,6 +22,14 @@ Global
{E004A114-54E0-B15C-BDA5-46681084E257}.Release|Win32.Build.0 = Release|Win32
{E004A114-54E0-B15C-BDA5-46681084E257}.Release|x64.ActiveCfg = Release|x64
{E004A114-54E0-B15C-BDA5-46681084E257}.Release|x64.Build.0 = Release|x64
+ {08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}.Debug|Win32.Build.0 = Debug|Win32
+ {08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}.Debug|x64.ActiveCfg = Debug|x64
+ {08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}.Debug|x64.Build.0 = Debug|x64
+ {08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}.Release|Win32.ActiveCfg = Release|Win32
+ {08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}.Release|Win32.Build.0 = Release|Win32
+ {08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}.Release|x64.ActiveCfg = Release|x64
+ {08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/gedosato_shim/gedosato_shim.vcxproj b/gedosato_shim/gedosato_shim.vcxproj
new file mode 100644
index 0000000..b2bd9ed
--- /dev/null
+++ b/gedosato_shim/gedosato_shim.vcxproj
@@ -0,0 +1,182 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ {08FFDAD8-A9DC-4662-9419-1FB5D3B5B6B0}
+ Win32Proj
+ gedosato_shim
+ 8.1
+
+
+
+ DynamicLibrary
+ true
+ v140
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v140_xp
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v140
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v140
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ gedoshim
+
+
+ true
+ gedoshim
+
+
+ false
+ gedoshim
+
+
+ false
+ gedoshim
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;GEDOSATO_SHIM_EXPORTS;%(PreprocessorDefinitions)
+ false
+
+
+ Windows
+ true
+ kernel32.lib
+ true
+ DllMain
+
+
+ copy "$(TargetPath)" "$(ProjectDir)..\pack"
+
+
+
+
+
+
+ Level3
+ Disabled
+ _DEBUG;_WINDOWS;_USRDLL;GEDOSATO_SHIM_EXPORTS;%(PreprocessorDefinitions)
+ false
+
+
+ Windows
+ true
+ kernel32.lib
+ true
+ DllMain
+
+
+ copy "$(TargetPath)" "$(ProjectDir)..\pack"
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;GEDOSATO_SHIM_EXPORTS;%(PreprocessorDefinitions)
+ false
+
+
+ Windows
+ true
+ true
+ true
+ kernel32.lib
+ true
+ DllMain
+
+
+ copy "$(TargetPath)" "$(ProjectDir)..\pack"
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_WINDOWS;_USRDLL;GEDOSATO_SHIM_EXPORTS;%(PreprocessorDefinitions)
+ false
+
+
+ Windows
+ true
+ true
+ true
+ kernel32.lib
+ true
+ DllMain
+
+
+ copy "$(TargetPath)" "$(ProjectDir)..\pack"
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gedosato_shim/gedosato_shim.vcxproj.filters b/gedosato_shim/gedosato_shim.vcxproj.filters
new file mode 100644
index 0000000..e71e3ef
--- /dev/null
+++ b/gedosato_shim/gedosato_shim.vcxproj.filters
@@ -0,0 +1,22 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;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
+
+
+
\ No newline at end of file
diff --git a/gedosato_shim/pack b/gedosato_shim/pack
new file mode 100644
index 0000000..21229da
Binary files /dev/null and b/gedosato_shim/pack differ
diff --git a/gedosato_shim/shim.cpp b/gedosato_shim/shim.cpp
new file mode 100644
index 0000000..a555894
--- /dev/null
+++ b/gedosato_shim/shim.cpp
@@ -0,0 +1,213 @@
+
+// This is a "shim" dll for loading GeDoSaTo into whitelisted programs
+//
+// It is designed to be minimally invasive, as it will be loaded into every process which loads user32.dll
+// Therefore, its only dependencies are on kernel32.dll, no CRT or other Windows libs.
+//
+// General workflow:
+// 1) On DLL_PROCESS_ATTACH:
+// 1.1) DisableThreadLibraryCalls
+// 1.2) Create a Hooking Thread
+// 1.3) Return
+// 2) In the hooking thread:
+// 2.1) Determine dll path and exe name
+// 2.2) load the whitelist files and check executable name against their patterns
+// 2.3) if there's a match, load the actual gedosato.dll
+// 2.4) FreeLibraryAndExitThread
+
+#define WIN32_LEAN_AND_MEAN
+#include
+
+#if 1
+#define DBG(__str) OutputDebugString(__str)
+#define DBGA(__str) OutputDebugStringA(__str)
+#else
+#define DBG(__str)
+#define DBGA(__str)
+#endif
+
+#define PATH_SIZE 256
+#define SHIM_DLL_NAME L"gedoshim.dll"
+#define MAIN_GEDO_DLL_NAME L"GeDoSaTo.dll"
+#define BAIL_ON(__condition, __msg) if(__condition) { DBG(__msg); return false; }
+
+typedef void(__cdecl *gedosatoInitFuncType)();
+
+// Yay C string processing without any libraries! Not annoying at all.
+#pragma region String processing
+
+bool matchWildcard(char *subject, char *pattern) {
+ for(; *pattern; pattern++) {
+ switch(*pattern) {
+ case '*':
+ if(*(pattern + 1) == '\0') {
+ // This wildcard appears at the end of the pattern.
+ // If we made it this far already, the match succeeds regardless of what the rest of the subject looks like.
+ return true;
+ }
+ for(char *s = subject; *s; s++) {
+ if(matchWildcard(s, pattern + 1)) return true;
+ }
+ return false;
+ case '?':
+ if(*(subject++) == '\0') return false;
+ break;
+ default:
+ if(*subject == '\0' || *pattern != *(subject++)) {
+ return false;
+ }
+ }
+ }
+ // End of pattern reached. If this also the end of the subject, then match succeeds.
+ return *subject == '\0';
+}
+
+bool checkWhitelistEntries(char* whitelistBuffer, LPCTSTR exeFileName) {
+ // convert exe file name
+ char exeFn[PATH_SIZE];
+ char defChr = '?';
+ auto convRet = WideCharToMultiByte(CP_ACP, 0, exeFileName, -1, exeFn, PATH_SIZE, &defChr, NULL);
+ BAIL_ON(convRet == 0, L"gedosato_shim: could not convert exe name to ANSI\r\n");
+ DBG(L"gedosato_shim: converted exe file name:\r\n"); DBGA(exeFn);
+
+ DBG(L"gedosato_shim: checking whitelist:\r\n"); DBGA(whitelistBuffer);
+
+ char *wListCur = whitelistBuffer, *curStart = nullptr, *lastNonWs = nullptr;
+ while(*wListCur != '\0') {
+ switch(*wListCur) {
+ case '#': // comment until EOL
+ DBG(L"gedosato_shim: -- skipping comment.\r\n");
+ while(*wListCur != '\0' && *wListCur != '\n') wListCur++;
+ break;
+ case '\r': // skip empty lines
+ case '\n':
+ DBG(L"gedosato_shim: -- skipping empty line.\r\n");
+ wListCur++;
+ break;
+ default: // extract executable pattern (start until last non-whitespace before | or newline)
+ DBG(L"gedosato_shim: -- handling new entry.\r\n");
+ curStart = wListCur;
+ lastNonWs = nullptr;
+ while(*wListCur != '\0' && *wListCur != '|' && *wListCur != '\n' && *wListCur != '\r') {
+ if(*wListCur != '\t' && *wListCur != ' ') lastNonWs = wListCur;
+ wListCur++;
+ }
+ if(*wListCur != '\0') wListCur++;
+ if(lastNonWs) {
+ lastNonWs[1] = '\0';
+ DBGA(curStart);
+ // check this pattern against exeName
+ if(matchWildcard(exeFn, curStart)) return true;
+ // consume until EOL
+ while(*wListCur != '\0' && *wListCur != '\n') wListCur++;
+ }
+ else {
+ DBG(L"gedosato_shim: -- no lastNonWS.\r\n");
+ }
+ }
+ }
+ return false;
+}
+
+#pragma endregion
+
+bool checkWhitelist(LPCTSTR directory, LPCTSTR fileName, LPCTSTR exeFileName) {
+ // build path whitelist
+ TCHAR listPath[PATH_SIZE*2];
+ lstrcpy(listPath, directory);
+ lstrcat(listPath, fileName);
+ DBG(L"gedosato_shim: loading whitelist:\r\n"); DBG(listPath);
+
+ // open whitelist file for reading and determine size
+ HANDLE file = CreateFile(listPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ BAIL_ON(file == INVALID_HANDLE_VALUE, L"gedosato_shim: could not open whitelist file for reading\r\n");
+ LARGE_INTEGER whitelistSize;
+ BOOL gotFileSize = GetFileSizeEx(file, &whitelistSize);
+ BAIL_ON(gotFileSize == FALSE, L"gedosato_shim: could not determine whitelist size\r\n");
+ DBG(L"gedosato_shim: opened whitelist.\r\n");
+
+ // read file and close
+ LPVOID buffer = HeapAlloc(GetProcessHeap(), 0, (SIZE_T)whitelistSize.QuadPart+1);
+ BAIL_ON(buffer == NULL, L"gedosato_shim: could not allocate buffer to load whitelist\r\n");
+ DWORD bytesRead;
+ BOOL readFile = ReadFile(file, buffer, (SIZE_T)whitelistSize.QuadPart, &bytesRead, NULL);
+ BAIL_ON(readFile == FALSE, L"gedosato_shim: failed to read whitelist file\r\n");
+ CloseHandle(file);
+ DBG(L"gedosato_shim: read whitelist.\r\n");
+
+ // process buffer
+ char* whitelistBuffer = (char*)buffer;
+ whitelistBuffer[whitelistSize.QuadPart] = '\0';
+ bool ret = checkWhitelistEntries(whitelistBuffer, exeFileName);
+ DBG(L"gedosato_shim: processed whitelist.\r\n");
+
+ // free buffer and return
+ HeapFree(GetProcessHeap(), 0, buffer);
+ return ret;
+}
+
+bool hookIfRequired(HMODULE hModule) {
+ // retrieve the fully qualified dll path
+ TCHAR dllPath[PATH_SIZE];
+ auto dllPathSize = GetModuleFileName(hModule, dllPath, PATH_SIZE);
+ BAIL_ON(dllPathSize == 0 || dllPathSize == PATH_SIZE, L"gedosato_shim: could not retreive dll path\r\n");
+ DBG(L"gedosato_shim: dll path:\r\n"); DBG(dllPath);
+
+ // get dll directory from path
+ auto dllPathIndex = FindStringOrdinal(FIND_FROMSTART, dllPath, -1, SHIM_DLL_NAME, -1, TRUE);
+ BAIL_ON(dllPathIndex <= 0, L"gedosato_shim: dll path unexpected end\r\n");
+ dllPath[dllPathIndex] = '\0';
+ DBG(L"gedosato_shim: dll directory:\r\n"); DBG(dllPath);
+
+ // retrieve the executable name of the process
+ TCHAR exePath[PATH_SIZE];
+ auto exePathSize = GetModuleFileName(NULL, exePath, PATH_SIZE);
+ BAIL_ON(exePathSize == 0 || exePathSize == PATH_SIZE, L"gedosato_shim: could not retreive exe path\r\n");
+ DBG(L"gedosato_shim: exe path:\r\n"); DBG(exePath);
+ auto exeIndex = FindStringOrdinal(FIND_FROMEND, exePath, -1, L"\\", 1, TRUE);
+ BAIL_ON(exeIndex <= 0, L"gedosato_shim: exe path directory end not found\r\n");
+ TCHAR* exeFileName = exePath + exeIndex + 1;
+ exeIndex = FindStringOrdinal(FIND_FROMEND, exeFileName, -1, L".exe", 1, TRUE);
+ BAIL_ON(exeIndex <= 0, L"gedosato_shim: exe file ending not found\r\n");
+ exeFileName[exeIndex] = '\0';
+ DBG(L"gedosato_shim: exe file name:\r\n"); DBG(exeFileName);
+
+ // check whitelists
+ bool whitelisted = checkWhitelist(dllPath, L"config\\whitelist.txt", exeFileName) || checkWhitelist(dllPath, L"config\\whitelist_user.txt", exeFileName);
+ if(whitelisted) {
+ DBG(L"gedosato_shim: whitelisted!\r\n");
+ // build dll path
+ TCHAR mainDllPath[PATH_SIZE * 2];
+ lstrcpy(mainDllPath, dllPath);
+ lstrcat(mainDllPath, MAIN_GEDO_DLL_NAME);
+ DBG(L"gedosato_shim: loading main dll:\r\n"); DBG(mainDllPath);
+ // perform actual hooking
+ HMODULE mainDllModule = LoadLibrary(mainDllPath);
+ BAIL_ON(mainDllModule <= 0, L"gedosato_shim: could not load main GeDoSaTo dll\r\n");
+ gedosatoInitFuncType initFunc = (gedosatoInitFuncType)GetProcAddress(mainDllModule, "GeDoSaToInit");
+ BAIL_ON(mainDllModule <= 0, L"gedosato_shim: could not resolve initialization procedure address\r\n");
+ initFunc();
+ DBG(L"gedosato_shim: done.\r\n");
+ return true;
+ }
+ else {
+ DBG(L"gedosato_shim: not whitelisted!\r\n");
+ }
+ return false;
+}
+
+DWORD hookThread(LPVOID hModule) {
+ hookIfRequired((HMODULE)hModule);
+ FreeLibraryAndExitThread((HMODULE)hModule, 0);
+ return 0;
+}
+
+BOOL WINAPI DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) {
+ if(fdwReason == DLL_PROCESS_ATTACH) {
+ DisableThreadLibraryCalls(hModule);
+ DBG(L"gedosato_shim: DllMain create thread\r\n");
+ HANDLE hookThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&hookThread, (LPVOID)hModule, 0, NULL);
+ SetThreadPriority(hookThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
+ }
+ return TRUE;
+}
diff --git a/pack/gedoshim.dll b/pack/gedoshim.dll
new file mode 100644
index 0000000..7f9e647
Binary files /dev/null and b/pack/gedoshim.dll differ