1 /*
2  * PROJECT:     ReactOS 'General' Shim library
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Ignore FreeLibrary calls
5  * COPYRIGHT:   Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #define WIN32_NO_STATUS
9 #include <windef.h>
10 #include <winbase.h>
11 #include <shimlib.h>
12 #include <strsafe.h>
13 
14 
15 #define SHIM_NS         IgnoreFreeLibrary
16 #include <setup_shim.inl>
17 
18 typedef BOOL(WINAPI* FREELIBRARYPROC)(HMODULE);
19 
20 const char** g_Names;
21 static int g_NameCount;
22 
23 BOOL WINAPI SHIM_OBJ_NAME(FreeLibrary)(HMODULE hModule)
24 {
25     char Buffer[MAX_PATH], *Ptr = Buffer;
26     DWORD len, wanted = ARRAYSIZE(Buffer);
27     for (;;)
28     {
29         len = GetModuleFileNameA(hModule, Ptr, wanted);
30         if (len < wanted)
31             break;
32 
33         wanted *= 2;
34         if (Ptr != Buffer)
35             ShimLib_ShimFree(Ptr);
36 
37         Ptr = ShimLib_ShimMalloc(wanted);
38         if (!Ptr)
39             break;
40     }
41 
42     if (Ptr && len)
43     {
44         char* ModuleName = NULL;
45         int n;
46         for (; len; len--)
47         {
48             ModuleName = Ptr + len;
49             if (ModuleName[-1] == '/' || ModuleName[-1] == '\\')
50                 break;
51         }
52         for (n = 0; n < g_NameCount; ++n)
53         {
54             if (!stricmp(g_Names[n], ModuleName))
55             {
56                 SHIM_INFO("Prevented unload of %s\n", ModuleName);
57                 if (Ptr && Ptr != Buffer)
58                     ShimLib_ShimFree(Ptr);
59                 return TRUE;
60             }
61         }
62     }
63 
64     if (Ptr && Ptr != Buffer)
65         ShimLib_ShimFree(Ptr);
66 
67     return CALL_SHIM(0, FREELIBRARYPROC)(hModule);
68 }
69 
70 static VOID InitIgnoreFreeLibrary(PCSTR CommandLine)
71 {
72     PCSTR prev, cur;
73     int count = 1, n = 0;
74     const char** names;
75 
76     if (!CommandLine || !*CommandLine)
77         return;
78 
79     prev = CommandLine;
80     while ((cur = strchr(prev, ';')))
81     {
82         count++;
83         prev = cur + 1;
84     }
85 
86     names = ShimLib_ShimMalloc(sizeof(char*) * count);
87     if (!names)
88     {
89         SHIM_WARN("Unable to allocate %u bytes\n", sizeof(char*) * count);
90         return;
91     }
92 
93     prev = CommandLine;
94     while ((cur = strchr(prev, ';')))
95     {
96         names[n] = ShimLib_StringNDuplicateA(prev, cur - prev + 1);
97         if (!names[n])
98         {
99             SHIM_WARN("Unable to allocate %u bytes\n", cur - prev + 2);
100             goto fail;
101         }
102         n++;
103         prev = cur + 1;
104     }
105     names[n] = ShimLib_StringDuplicateA(prev);
106     if (!names[n])
107     {
108         SHIM_WARN("Unable to allocate last string\n");
109         goto fail;
110     }
111 
112     g_Names = names;
113     g_NameCount = count;
114     return;
115 
116 fail:
117     --n;
118     while (n >= 0)
119     {
120         if (names[n])
121             ShimLib_ShimFree((PVOID)names[n]);
122 
123         --n;
124     }
125     ShimLib_ShimFree(names);
126 }
127 
128 BOOL WINAPI SHIM_OBJ_NAME(Notify)(DWORD fdwReason, PVOID ptr)
129 {
130     if (fdwReason == SHIM_NOTIFY_ATTACH)
131     {
132         SHIM_MSG("IgnoreFreeLibrary(%s)\n", SHIM_OBJ_NAME(g_szCommandLine));
133         InitIgnoreFreeLibrary(SHIM_OBJ_NAME(g_szCommandLine));
134     }
135     return TRUE;
136 }
137 
138 
139 #define SHIM_NOTIFY_FN SHIM_OBJ_NAME(Notify)
140 #define SHIM_NUM_HOOKS  1
141 #define SHIM_SETUP_HOOKS \
142     SHIM_HOOK(0, "KERNEL32.DLL", "FreeLibrary", SHIM_OBJ_NAME(FreeLibrary))
143 
144 #include <implement_shim.inl>
145