1 #undef UNICODE
2 #undef _UNICODE
3 
4 #pragma once
5 
6 #ifdef _MSC_VER
7 #pragma warning(push, 1) /* disable warnings within system headers */
8 #endif
9 #define WIN32_LEAN_AND_MEAN
10 #include <windows.h>
11 #include <msiquery.h>
12 #include <imagehlp.h>
13 #include <tchar.h>
14 #include <strsafe.h>
15 #ifdef _MSC_VER
16 #pragma warning(pop)
17 #endif
18 
19 #include <malloc.h>
20 #include <time.h>
21 #include <string>
22 #include <hash_map>
23 
24 const DWORD PE_Signature = 0x00004550;
25 typedef std::pair< std::string, bool > StringPair;
26 typedef	std::hash_map< std::string, bool > ExcludeLibsMap;
27 
28 #ifdef DEBUG
29 static void OutputDebugStringFormat( LPCSTR pFormat, ... )
30 {
31 	CHAR    buffer[1024];
32 	va_list args;
33 
34 	va_start( args, pFormat );
35 	StringCchVPrintfA( buffer, sizeof(buffer), pFormat, args );
36 	OutputDebugStringA( buffer );
37 }
38 #else
39 static void OutputDebugStringFormat( LPCSTR, ... )
40 {
41 }
42 #endif
43 
44 static bool IsValidHandle( HANDLE handle )
45 {
46 	return NULL != handle && INVALID_HANDLE_VALUE != handle;
47 }
48 
49 static std::string GetMsiProperty(MSIHANDLE handle, const std::string& sProperty)
50 {
51 	std::string result;
52     TCHAR		szDummy[1] = TEXT("");
53     DWORD		nChars = 0;
54 
55     if (MsiGetProperty(handle, sProperty.c_str(), szDummy, &nChars) == ERROR_MORE_DATA)
56     {
57         DWORD nBytes = ++nChars * sizeof(TCHAR);
58         LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes));
59         ZeroMemory( buffer, nBytes );
60         MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars);
61         result = buffer;
62     }
63     return result;
64 }
65 
66 static BOOL rebaseImage( const std::string& filePath, LPVOID address )
67 {
68 	ULONG ulOldImageSize;
69 	ULONG_PTR lpOldImageBase;
70 	ULONG ulNewImageSize;
71 	ULONG_PTR lpNewImageBase = reinterpret_cast<ULONG_PTR>(address);
72 
73 	BOOL bResult = ReBaseImage(
74 		filePath.c_str(),
75 		"",
76 		TRUE,
77 		FALSE,
78 		FALSE,
79 		0,
80 		&ulOldImageSize,
81 		&lpOldImageBase,
82 		&ulNewImageSize,
83 		&lpNewImageBase,
84 		(ULONG)time(NULL) );
85 
86 	return bResult;
87 }
88 
89 static BOOL rebaseImage( MSIHANDLE /*handle*/, const std::string& sFilePath, LPVOID address )
90 {
91 	std::string	mystr;
92 	mystr = "Full file: " + sFilePath;
93 
94 	BOOL bResult = rebaseImage( sFilePath, address );
95 
96 	if ( !bResult )
97 	{
98 		OutputDebugStringFormat( "Rebasing library %s failed", mystr.c_str() );
99 	}
100 
101 	return bResult;
102 }
103 
104 static BOOL rebaseImagesInFolder( MSIHANDLE handle, const std::string& sPath, LPVOID address, ExcludeLibsMap& rExcludeMap )
105 {
106 	std::string     sDir     = sPath;
107 	std::string	    sPattern = sPath + TEXT("*.dll");
108 	WIN32_FIND_DATA	aFindFileData;
109 
110 	HANDLE hFind = FindFirstFile( sPattern.c_str(), &aFindFileData );
111 	if ( IsValidHandle(hFind) )
112 	{
113 		BOOL fSuccess = false;
114 
115 		do
116 		{
117 			std::string sFileName = aFindFileData.cFileName;
118 			if ( rExcludeMap.find( sFileName ) == rExcludeMap.end() )
119 			{
120 				OutputDebugStringFormat( "Rebase library: %s", sFileName.c_str() );
121                 std::string	sLibFile = sDir +  sFileName;
122                 rebaseImage( handle, sLibFile, address );
123 			}
124 			else
125 			{
126 				OutputDebugStringFormat( "Exclude library %s from rebase", sFileName.c_str() );
127 			}
128 
129 			fSuccess = FindNextFile( hFind, &aFindFileData );
130 		}
131 		while ( fSuccess );
132 
133 		FindClose( hFind );
134 	}
135 
136 	return ERROR_SUCCESS;
137 }
138 
139 static BOOL rebaseImages( MSIHANDLE handle, LPVOID pAddress, ExcludeLibsMap& rMap )
140 {
141 	std::string sInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION"));
142 
143 	std::string sBasisDir  = sInstallPath + TEXT("Basis\\program\\");
144 	std::string sOfficeDir = sInstallPath + TEXT("program\\");
145 	std::string sUreDir    = sInstallPath + TEXT("URE\\bin\\");
146 
147 	BOOL bResult = rebaseImagesInFolder( handle, sBasisDir, pAddress, rMap );
148 	bResult &= rebaseImagesInFolder( handle, sOfficeDir, pAddress, rMap );
149 	bResult &= rebaseImagesInFolder( handle, sUreDir, pAddress, rMap );
150 
151 	return bResult;
152 }
153 
154 static BOOL IsServerSystem( MSIHANDLE /*handle*/ )
155 {
156 	OSVERSIONINFOEX osVersionInfoEx;
157 	osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
158 	GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osVersionInfoEx));
159 
160 	if ( osVersionInfoEx.wProductType != VER_NT_WORKSTATION )
161 	{
162         OutputDebugStringFormat( "Server system detected. No rebase necessary!" );
163 		return TRUE;
164 	}
165 	else
166     {
167         OutputDebugStringFormat( "Client system detected. Rebase necessary!" );
168         return FALSE;
169     }
170 }
171 
172 static void InitExcludeFromRebaseList( MSIHANDLE handle, ExcludeLibsMap& rMap )
173 {
174 	size_t      nPos( 0 );
175     const TCHAR cDelim = ',';
176 	std::string sLibsExcluded = GetMsiProperty(handle, TEXT("EXCLUDE_FROM_REBASE"));
177 
178     while ( nPos < sLibsExcluded.size() )
179 	{
180 	    size_t nDelPos = sLibsExcluded.find_first_of( cDelim, nPos );
181 
182 		std::string sExcludedLibName;
183 		if ( nDelPos != std::string::npos )
184 		{
185 			sExcludedLibName = sLibsExcluded.substr( nPos, nDelPos - nPos );
186 		    nPos = nDelPos+1;
187 		}
188 		else
189 		{
190 			sExcludedLibName = sLibsExcluded.substr( nPos );
191 			nPos = sLibsExcluded.size();
192 		}
193 
194 		if ( sExcludedLibName.size() > 0 )
195 		{
196 			OutputDebugStringFormat( "Insert library %s into exclude from rebase list", sExcludedLibName.c_str() );
197 			rMap.insert( StringPair( sExcludedLibName, true ));
198 		}
199 	}
200 }
201 
202 extern "C" BOOL __stdcall RebaseLibrariesOnProperties( MSIHANDLE handle )
203 {
204 	static LPVOID pDefault = reinterpret_cast<LPVOID>(0x10000000);
205 
206 	OutputDebugStringFormat( "RebaseLibrariesOnProperties has been called" );
207 	std::string sDontOptimizeLibs = GetMsiProperty(handle, TEXT("DONTOPTIMIZELIBS"));
208 	if ( sDontOptimizeLibs.length() > 0 && sDontOptimizeLibs == "1" )
209 	{
210         OutputDebugStringFormat( "Don't optimize libraries set. No rebase necessary!" );
211 		return TRUE;
212 	}
213 
214 	if ( !IsServerSystem( handle ))
215 	{
216 		ExcludeLibsMap aExcludeLibsMap;
217 		InitExcludeFromRebaseList( handle, aExcludeLibsMap );
218 
219 		return rebaseImages( handle, pDefault, aExcludeLibsMap );
220 	}
221 
222 	return TRUE;
223 }
224