51Degrees GPU render technique allows web developers and analysts to accurately identify Apple Devices once again
We've released it as an open source project and are confident it will allow web developers and analysts to accurately identify Apple devices once again.
The Solution
Following on from our previous blog on Apple obfuscating GPU models within Apple User Agents, 51Degrees now has a Mozilla Public Licenced 2 solution for identifying the GPU model and therefore the exact iPhone or iPad model.
The technique leverages hardware defined interpolation methods and sample patterns, which vary from one GPU to another, to measure pixel values of an image rendered by a certain GPU. While images on different devices may look identical to a user, there are subtle differences in some of the pixels.
To generate the data needed to uniquely identify a GPU within a set of GPUs, a rendering method is used to draw a complex 2d vector image. A canvas element is created within a web page in a browser and subsequently drawn to.
A simple line which is horizontal or vertical is unlikely to be rendered any differently on different GPUs. However, as can be seen in Figures 1 and 2, when a diagonal line is rendered the GPU must determine how best to shade pixels in order for the line to appear straight.
Each GPU will determine which pixels will be shaded, and to what degree, differently to other GPUs. If we identify the shade of each pixel by a byte value between 0 and 255 (as this image is in greyscale), it is obvious in this exaggerated example, that the values of the pixels in each figure can be used to uniquely identify each.
While this example may not extend to a particularly large set of GPUs, larger sets can be distinguished uniquely by increasing the complexity of the shapes to render. For example, adding shading and gradients is an effective method of creating a unique set of pixel values for each GPU in a set.
In practice, pixel values are not stored as a single byte value, but a combination of three bytes representing the red, green and blue components of the pixel's colour. As this is still just a numerical representation of the pixel, the same logic applies.
The following JavaScript is used to draw the image shown in Figure 3.
// Draws an image that changes very subtly based on the GPU model used
// to render it.
// @param a canvas instance that has not be drawn to.
// @return a base 64 encoded string containing the image.
function drawImage(canvas) {
// Configure the canvas and get context.
canvas.width = 67;
canvas.height = 67;
var ctx = canvas.getContext('2d', { alpha: true });
if (ctx != null) {
// Configure the canvas context.
ctx.imageSmoothingQuality = "low";
ctx.imageSmoothingEnabled = true;
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1;
ctx.miterLimit = Infinity;
ctx.filter = "none";
ctx.lineCap = "butt";
ctx.lineDashOffset = 0;
ctx.lineJoin = "miter";
ctx.font = "10pt Arial";
ctx.lineWidth = 2;
// setLineDash not supported on iPhone 3G / iOS 4.2
if (ctx.setLineDash !==undefined) {
ctx.setLineDash([10, 20]);
}
ctx.shadowColor = "black";
ctx.shadowOffsetX = -3;
ctx.shadowOffsetY = -5;
// Rotate the canvas and add some text.
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(0.8901179);
ctx.fillStyle = "green";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("*51Degrees*", 0, 0);
// Draw a transparent circle or elipse over the text. A circle
// is used if the ellipse feature is not supported by the GPU.
ctx.beginPath();
ctx.shadowColor = "yellow";
ctx.shadowBlur = 1;
ctx.shadowOffsetX = 1;
ctx.shadowOffsetY = 1;
ctx.strokeStyle = "red";
ctx.fillStyle = "rgba(0, 0, 255, 0.6)";
if (ctx.ellipse === undefined) {
ctx.arc(0, 0, 25, 0, 2 * Math.PI);
}
else {
ctx.ellipse(0, 0, 25, 15, Math.PI / 4, 0, 2 * Math.PI);
}
ctx.fill();
ctx.stroke();
// Return the image as a base 64 encoded string.
return canvas.toDataURL();
}
}
The rendered image is then returned as a byte array represented as a string using the canvas.toDataURL() method.
This value is then hashed using the FNV hashing algorithm to give an integer value unique to each GPU in the set.
Device | Screen Width | Screen Height | Hash Code | GPU Model |
iPhone 5C | 640 | 1136 | 439591115 | PowerVR SGX 543 MP3 |
---|---|---|---|---|
iPhone 8 | 750 | 1334 | 3512764074 | Apple A11 Bionic GPU |
iPhone X | 1125 | 2436 | 3512764074 | Apple A11 Bionic GPU |
iPhone 6S | 750 | 1334 | 3354180376 | PowerVR GT 7600 |
iPhone 6 | 750 | 1334 | 4130174414 | PowerVR GX 6450 |
iPhone 3GS | 320 | 480 | 3389563912 | PowerVR SGX 535 |
It can be seen from Table 1 that each GPU can be uniquely identified using the hash code alone. For uniquely identifying the device itself, more information is needed. This is described in more depth in the iPhone detection blog post. Neither the hash code nor the screen resolution alone can uniquely identify all the devices in the set.
For example, the iPhone 6 and iPhone 6S share the same screen size, and the iPhone 8 and iPhone X share the same GPU (and subsequently hash code). However, the combination of the hash code and the screen resolution can uniquely identify all the devices in the set.
Optimization
Some rendering instructions have limits in a certain set of GPUs. For example, blurring, if used too liberally, can result in random differences. If the blur implementation is a Gaussian blur, there will be many floating point approximations which depend on the GPUs bus size, the approximated value of π, the approximation of square roots, division, and exponential functions.
The result of this would not change when run again on the same GPU. However, if the blur function introduced even the slightest randomisation, a second result would differ on the same GPU. This is the case on some GPUs when applying a blur across a large area.
In addition to the blurring example, there are many other variables which must be considered, and the difference between a rendered image which cannot uniquely identify the entire set, and one which may produce random results on some GPUs (ultimately leading to the inability to uniquely identify the entire set), can be a fine line.
By knowing the set which needs to be differentiated, and carrying out rigorous tests, the optimal rendering instructions can be achieved for that particular set. It is important to note that this can only be considered optimal for the set, or subset therein. This means that for the detection to be valid, the device must be known to belong to the set.
For example, with a set containing all Apple iPhone models, a device is determined as being within the set from the User Agent alone using the 51Degrees API. The primary targets for this technique are Apple mobile devices, so the sets include iPhones and iPads.
On top of looking at the resulting render, the method also looks at what can and can't be done by the device. For example, the fact that some versions of Safari can render an ellipse while others can't, provides a great deal of information. This is a simple yes or no, but the fact that older devices cannot be updated to new software versions that support ellipses splits the set into two distinct subsets without even carrying out any rendering.
There may, however, be occasions where the exact model of iPhone or iPad will not be possible to identify. In those cases, we will provide a group of possible devices. Here is a list of the groups that may be returned, if we can't precisely identify the device:
- iPhone 6S and iPhone 7
- iPhone 6S Plus and iPhone 7 Plus
- iPhone 6S, iPhone 7 and iPhone SE - this group will be returned if either the 6S or 7 is in 'zoom' mode
- iPhone X, iPhone XS, and iPhone XS Max - this group will be returned if the XS Max is in 'zoom' mode
- iPad Pro 12.9 and iPad Pro 12.9 2nd generation
- iPad 5, iPad 6, iPad Pro 9.7 iPad Pro 12.9 and iPad Pro 12.9 2nd generation - this group will be returned if either the 12.9 or 12.9 2nd generation is in 'zoom' mode
- iPad Air 2 and iPad mini 4
- iPad Air 1, iPad mini 2 and iPad mini 3
- iPad, iPad 2 (Wi-Fi)
We will be working on ensuring the greatest level of granularity over the coming months, and we'll post an update as soon as there have been new developments.
Try it for yourself
Test the solution for yourself. The open source code used is available on GitHub and is licensed for you to use under the Mozilla Public License 2 (just like the Firefox browser). The techniques described in this blog are the subject of United Kingdom Patent Application No. 1905888.2.
51Degrees device intelligence is the world's fastest and most accurate device detection solution for your website today, tomorrow and in the future. If you'd like to find out more please contact us and we'll be happy to discuss how we can help you maximize your business potential.
51Degrees enables you to detect over 55,000 different device models; allowing you to optimize your website and increase revenue.