Skip to content

Commit c67ac66

Browse files
committed
Add a SHA256 hash to verify on load.
1 parent 3bfefbd commit c67ac66

File tree

4 files changed

+42
-97
lines changed

4 files changed

+42
-97
lines changed

analytics/generate_windows_stubs.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"""Generate stubs and function pointers for Windows SDK"""
1717

1818
import argparse
19+
import hashlib
1920
import os
2021
import re
2122
import sys
@@ -39,17 +40,29 @@
3940
4041
"""
4142

42-
def generate_function_pointers(header_file_path, output_h_path, output_c_path):
43+
44+
def hash_file(filename):
45+
sha256_hash = hashlib.sha256()
46+
with open(filename, "rb") as file:
47+
while chunk := file.read(4096):
48+
sha256_hash.update(chunk)
49+
return sha256_hash.hexdigest()
50+
51+
def generate_function_pointers(dll_file_path, header_file_path, output_h_path, output_c_path):
4352
"""
4453
Parses a C header file to generate a self-contained header with typedefs,
4554
extern function pointer declarations, and a source file with stub functions,
4655
initialized pointers, and a dynamic loading function for Windows.
4756
4857
Args:
58+
header_file_path (str): The path to the DLL file.
4959
header_file_path (str): The path to the input C header file.
5060
output_h_path (str): The path for the generated C header output file.
5161
output_c_path (str): The path for the generated C source output file.
5262
"""
63+
print(f"Reading DLL file: {dll_file_path}")
64+
dll_hash = hash_file(dll_file_path)
65+
5366
print(f"Reading header file: {header_file_path}")
5467
try:
5568
with open(header_file_path, 'r', encoding='utf-8') as f:
@@ -142,6 +155,8 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
142155
f.write("\n\n// --- Dynamic Loader Declaration for Windows ---\n")
143156
f.write("#if defined(_WIN32)\n")
144157
f.write('#include <windows.h> // For HMODULE\n')
158+
f.write(f'\n// Google Analytics Windows DLL SHA256 hash, to be verified on load.')
159+
f.write(f'\n#define FIREBASE_ANALYTICS_DYNAMIC_LIBRARY_HASH "{dll_hash}"\n')
145160
f.write(f'\n// Number of Google Analytics functions expected to be loaded from the DLL.')
146161
f.write(f'\n#define FIREBASE_ANALYTICS_DYNAMIC_FUNCTION_COUNT {len(function_details_for_loader)}\n\n')
147162
f.write('// Load Google Analytics functions from the given DLL handle into function pointers.\n')
@@ -205,6 +220,12 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
205220
parser = argparse.ArgumentParser(
206221
description="Generate C stubs and function pointers from a header file."
207222
)
223+
parser.add_argument(
224+
"--windows_dll",
225+
default = os.path.join(os.path.dirname(sys.argv[0]), "windows/analytics_win.dll"),
226+
#required=True,
227+
help="Path to the DLL file to calculate a hash."
228+
)
208229
parser.add_argument(
209230
"--windows_header",
210231
default = os.path.join(os.path.dirname(sys.argv[0]), "windows/include/public/c/analytics.h"),
@@ -223,10 +244,10 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
223244
#required=True,
224245
help="Path for the generated output source file."
225246
)
226-
227247
args = parser.parse_args()
228248

229249
generate_function_pointers(
250+
args.windows_dll,
230251
args.windows_header,
231252
args.output_header,
232253
args.output_source

analytics/src/analytics_desktop.cc

Lines changed: 15 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -34,79 +34,9 @@ namespace firebase {
3434
namespace analytics {
3535

3636
#if defined(_WIN32)
37-
#define ANALYTICS_DLL_DEFAULT_FILENAME L"analytics_win.dll"
38-
std::wstring g_analytics_dll_filename = ANALYTICS_DLL_DEFAULT_FILENAME;
39-
static HMODULE g_analytics_dll = 0;
40-
41-
// Function to convert a UTF-8 string to a wide character (UTF-16) string.
42-
std::wstring Utf8ToWide(const std::string& utf8String) {
43-
if (utf8String.empty()) {
44-
return std::wstring();
45-
}
46-
47-
// First, determine the required buffer size.
48-
int wideCharCount = MultiByteToWideChar(
49-
CP_UTF8, // Source code page (UTF-8)
50-
0, // Flags
51-
utf8String.c_str(), // Source UTF-8 string
52-
-1, // -1 indicates the string is null-terminated
53-
nullptr, // No buffer provided, we're calculating the size
54-
0 // Requesting the buffer size
55-
);
56-
57-
if (wideCharCount == 0) {
58-
// Handle error: GetLastError() can provide more details.
59-
LogError(
60-
"Error determining buffer size for UTF-8 to wide char conversion.");
61-
return std::wstring();
62-
}
63-
64-
// Allocate the wide character string.
65-
std::wstring wideString(wideCharCount, 0);
66-
67-
// Second, perform the actual conversion.
68-
int result =
69-
MultiByteToWideChar(CP_UTF8, // Source code page (UTF-8)
70-
0, // Flags
71-
utf8String.c_str(), // Source UTF-8 string
72-
-1, // -1 indicates the string is null-terminated
73-
&wideString[0], // Pointer to the destination buffer
74-
wideCharCount // The size of the destination buffer
75-
);
76-
77-
if (result == 0) {
78-
// Handle error: GetLastError() can provide more details.
79-
LogError("Error converting UTF-8 to wide char.");
80-
return std::wstring();
81-
}
82-
83-
// The returned wideString from MultiByteToWideChar will be null-terminated,
84-
// but std::wstring handles its own length. We might need to resize it
85-
// to remove the extra null character included in the count if we passed -1.
86-
size_t pos = wideString.find(L'\0');
87-
if (pos != std::wstring::npos) {
88-
wideString.resize(pos);
89-
}
90-
91-
return wideString;
92-
}
93-
94-
void SetAnalyticsLibraryPath(const char* path) {
95-
if (path) {
96-
g_analytics_dll_filename = Utf8ToWide(path);
97-
} else {
98-
g_analytics_dll_filename = ANALYTICS_DLL_DEFAULT_FILENAME;
99-
}
100-
}
37+
#define ANALYTICS_DLL_FILENAME L"analytics_win.dll"
10138

102-
void SetAnalyticsLibraryPath(const wchar_t* path) {
103-
if (path) {
104-
g_analytics_dll_filename = path;
105-
} else {
106-
g_analytics_dll_filename = ANALYTICS_DLL_DEFAULT_FILENAME;
107-
}
108-
}
109-
#endif
39+
static HMODULE g_analytics_module = 0;
11040

11141
// Future data for analytics.
11242
// This is initialized in `Initialize()` and cleaned up in `Terminate()`.
@@ -127,14 +57,18 @@ void Initialize(const App& app) {
12757
g_fake_instance_id = 0;
12858

12959
#if defined(_WIN32)
130-
if (!g_analytics_dll) {
131-
g_analytics_dll = LoadLibraryW(g_analytics_dll_filename.c_str());
132-
if (g_analytics_dll) {
133-
LogInfo("Loaded Google Analytics DLL");
60+
if (!g_analytics_module) {
61+
// Only allow the DLL to be loaded from the application directory.
62+
g_analytics_module = LoadLibraryExW(ANALYTICS_DLL_FILENAME, NULL,
63+
LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
64+
if (g_analytics_module) {
65+
LogInfo("Loaded Google Analytics module");
13466
int num_loaded = FirebaseAnalytics_LoadDynamicFunctions(g_analytics_dll);
13567
if (num_loaded < FIREBASE_ANALYTICS_DYNAMIC_FUNCTION_COUNT) {
136-
LogWarning("Only loaded %d out of %d expected functions from DLL.",
137-
num_loaded, FIREBASE_ANALYTICS_DYNAMIC_FUNCTION_COUNT);
68+
LogWarning(
69+
"Only loaded %d out of %d expected functions from the Google "
70+
"Analytics module.",
71+
num_loaded, FIREBASE_ANALYTICS_DYNAMIC_FUNCTION_COUNT);
13872
}
13973
} else {
14074
// Silently fail and continue in stub mode.
@@ -155,9 +89,9 @@ bool IsInitialized() { return g_initialized; }
15589
void Terminate() {
15690
#if defined(_WIN32)
15791
FirebaseAnalytics_UnloadDynamicFunctions();
158-
if (g_analytics_dll) {
159-
FreeLibrary(g_analytics_dll);
160-
g_analytics_dll = 0;
92+
if (g_analytics_module) {
93+
FreeLibrary(g_analytics_module);
94+
g_analytics_module = 0;
16195
}
16296
#endif
16397

analytics/src/analytics_desktop_dynamic.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ extern void (*ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled)(bool enabled);
116116
#if defined(_WIN32)
117117
#include <windows.h> // For HMODULE
118118

119+
// Google Analytics Windows DLL SHA256 hash, to be verified on load.
120+
#define FIREBASE_ANALYTICS_DYNAMIC_LIBRARY_HASH \
121+
"c1b9ff6e9119c30bbeb7472326dcde418f45682e6b822e25eed922fe6e3cc698"
122+
119123
// Number of Google Analytics functions expected to be loaded from the DLL.
120124
#define FIREBASE_ANALYTICS_DYNAMIC_FUNCTION_COUNT 19
121125

analytics/src/include/firebase/analytics.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -591,20 +591,6 @@ Future<int64_t> GetSessionId();
591591
/// app session.
592592
Future<int64_t> GetSessionIdLastResult();
593593

594-
#ifdef INTERNAL_EXPERIMENTAL
595-
#if defined(_WIN32) || defined(DOXYGEN)
596-
/// Windows only: Specify the path to the Google Analytics Windows DLL.
597-
///
598-
/// @param path Path to the DLL, including filename, in UTF-8 format.
599-
void SetAnalyticsLibraryPath(const char* path);
600-
601-
/// Windows only: Specify the path to the Google Analytics Windows DLL.
602-
///
603-
/// @param path Path to the DLL, including filename, in UTF-16 format.
604-
void SetAnalyticsLibraryPath(const wchar_t* path);
605-
#endif
606-
#endif
607-
608594
} // namespace analytics
609595
} // namespace firebase
610596

0 commit comments

Comments
 (0)