Media Noise (Canvas, WebGL, Audio)
Relevant source files
The following files were used as context for generating this wiki page:
The Media Noise system is a core component of GeekEZ Browser's fingerprinting defense. Its primary purpose is to add non-intrusive, randomized noise to media-related browser APIs, such as Canvas, WebGL, and AudioContext. This process creates a unique hardware hash for each browser profile, significantly enhancing its uniqueness and making it more difficult for tracking scripts to identify and link accounts.
This system works by generating specific noise and spoofing parameters when a new profile is created and then injecting this configuration into the browser instance at runtime. The injection is achieved natively through a dynamically generated Chrome extension, which avoids common detection vectors associated with direct JavaScript eval or postMessage injections.
Sources: README.md, fingerprint.js, main.js
Architecture and Data Flow
The media noise feature is implemented through a three-stage process: Generation, Injection, and Application.
- Generation: When a user creates a new profile, the
generateFingerprintfunction is called to create a set of unique values for media APIs. - Injection: Upon launching a profile, the
main.jsprocess dynamically creates a temporary Chrome extension named "GeekEZ Guard". The noise parameters are embedded within this extension's content script. - Application: The browser is launched with this custom extension loaded, which then hooks into the relevant JavaScript prototypes (e.g.,
CanvasRenderingContext2D.prototype.getImageData) to apply the noise in real-time.
The following diagram illustrates the data flow from profile creation to a running browser with media noise applied.
Sources: main.js:250-255, main.js:338-341, fingerprint.js:10-15
Fingerprint Generation
The core of the media noise system is the fingerprint object, which is generated by the generateFingerprint function in fingerprint.js. This object contains all the parameters needed to spoof various media and hardware attributes.
Sources: fingerprint.js:10-85
Fingerprint Object Structure
The following diagram shows the key properties within the fingerprint object related to media noise.
Sources: fingerprint.js:70-84
Key Parameters
The table below details the media-related properties generated for each profile.
| Property | Type | Description | Generation Logic |
|---|---|---|---|
webgl | Object | Contains spoofed WebGL vendor and renderer strings. | Hardcoded to vendor: 'Google Inc. (NVIDIA)' and renderer: 'ANGLE (NVIDIA)'. |
canvasNoise | Object | An object with r, g, b, a values for canvas pixel manipulation. | Each channel value is a random integer between -5 and 5. |
audioNoise | Number | A small floating-point number added to the AudioBuffer channel data. | A random float generated by Math.random() * 0.000001. |
noiseSeed | Number | A random integer used to determine which pixels are affected by canvas noise. | A random integer up to 9,999,999. |
Sources: fingerprint.js:50-57, fingerprint.js:81-83
Injection Mechanism
The fingerprint is not applied by directly modifying the browser's source code. Instead, it's injected at runtime using a dynamically generated Chrome extension.
- The
generateExtensionfunction inmain.jscreates a directory for the extension within the profile's folder. - It writes a
manifest.jsonfile defining the extension. - It calls
getInjectScript(fingerprint)fromfingerprint.jsto get the JavaScript payload. - This payload is written to a
content.jsfile inside the extension directory. - The browser is launched via Puppeteer with the
--load-extensionand--disable-extensions-exceptflags, ensuring only our "GeekEZ Guard" and user-approved extensions are active.
This sequence is illustrated below:
Sources: main.js:96-106, main.js:338-384
Media Spoofing Details
Canvas Noise
Canvas fingerprinting is mitigated by slightly altering the pixel data of the canvas element. The injection script overrides the CanvasRenderingContext2D.prototype.getImageData method.
When getImageData is called, the original function is executed first. Then, the script iterates through the pixel data. Using the noiseSeed, it selectively modifies the alpha channel (a) of certain pixels, adding the small random noise value defined in fp.canvasNoise.a. This introduces enough variance to make the canvas hash unique per profile without visibly distorting the image.
// Source: fingerprint.js:192-204
const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData;
CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
const imageData = originalGetImageData.apply(this, arguments);
if (fp.noiseSeed) {
for (let i = 0; i < imageData.data.length; i += 4) {
if ((i + fp.noiseSeed) % 53 === 0) {
const noise = fp.canvasNoise ? (fp.canvasNoise.a || 0) : 0;
imageData.data[i+3] = Math.max(0, Math.min(255, imageData.data[i+3] + noise));
}
}
}
return imageData;
};
Audio Noise
Similar to canvas, AudioContext fingerprinting is defeated by adding noise to the audio buffer. The script overrides AudioBuffer.prototype.getChannelData.
After the original channel data is retrieved, a very small floating-point audioNoise value is added to the first 100 samples of the buffer. This is sufficient to alter the resulting hash of the audio data while being completely inaudible.
// Source: fingerprint.js:207-216
const originalGetChannelData = AudioBuffer.prototype.getChannelData;
AudioBuffer.prototype.getChannelData = function(channel) {
const results = originalGetChannelData.apply(this, arguments);
const noise = fp.audioNoise || 0.0000001;
for (let i = 0; i < 100 && i < results.length; i++) {
results[i] = results[i] + noise;
}
return results;
};
WebGL Spoofing
WebGL fingerprinting often relies on the WebGL_debug_renderer_info extension, which exposes the GPU vendor and renderer strings. While the injection script in fingerprint.js does not show a direct hook for WebGL, the fingerprint object itself contains hardcoded values for the GPU.
The webgl property is generated with a static value to provide a consistent, common GPU profile rather than a randomized one.
// Source: fingerprint.js:49-50
// 显卡透传
const gpu = { vendor: 'Google Inc. (NVIDIA)', renderer: 'ANGLE (NVIDIA)' };
These values are made editable to the user through the profile settings modal.
Sources: fingerprint.js:49-50, renderer.js:659-660
User Configuration
While most noise parameters are fully randomized and hidden, the user has control over some key WebGL and noise seed values via the "Edit Profile" modal.
| UI Element ID | Label | Fingerprint Property | Description |
|---|---|---|---|
editGpuVendor | WebGL | fingerprint.webgl.vendor | The spoofed WebGL vendor string. |
editGpuRenderer | WebGL | fingerprint.webgl.renderer | The spoofed WebGL renderer string. |
editSeed | Seed | fingerprint.noiseSeed | The seed for the canvas noise algorithm. |
These fields allow advanced users to fine-tune their fingerprint to match specific hardware profiles or to regenerate noise values if needed.
Sources: index.html:1120-1123, renderer.js:659-662, renderer.js:683-685
Conclusion
The Media Noise system is a sophisticated and critical feature for ensuring profile uniqueness in GeekEZ Browser. By combining randomized parameter generation with a native extension-based injection mechanism, it effectively mitigates tracking via Canvas, AudioContext, and WebGL fingerprinting. The system is designed to be both effective and performant, applying minimal, non-intrusive modifications that are sufficient to defeat detection without compromising browser functionality or user experience.
Sources: README.md, fingerprint.js, main.js