Reverting annoying changes in the chromium web browser with binary patching!

Posted on May 26, 2016

I updated chromium today, and noticed an unwelcome change which made the “Let me choose when to run plugin content” option

in chrome://settings/content be ineffective for PDFium, the chromium PDF reader plugin:

I was mildly annoyed because I regularly keep huge PDFs 1 in my tabs to refer to them regularly – but only let PDFium run when i’m actively reading them, to avoid any performance impact. I found the appropriate changelog for chromium2 and found the relevant commit, whose description is:

Internal PDF viewer will always load if it is not disabled, even if
plugins are set to CONTENT_SETTING_BLOCK in content settings.

(That commit message doesn’t mention potential negative impact on performance, yaey).

The commit has two parts, some C++ code introducing a new plugin tag called “PluginMetadata::SECURITY_STATUS_FULLY_TRUSTED”, which when present on a plugin, creates the “you can’t enable click-to-run for this plugin, it’ll always run, want it or not” behavior (which we want to get rid of), but the part that actually tags the chromium PDF plugin with the fully_trusted tag is not in C++ code, it’s in some .json file:

-        "status": "up_to_date",
+        "status": "fully_trusted",

Now I’m thinking “oh I just need to edit that JSON file, so the PDF plugin doesn’t get tagged with fully_trusted, and I’ll get the desired behavior back!”.

Not so fast – I can’t find any JSON files belonging to chromium on my system! I ask my package manager what files the chromium package owns and find a large (20 megabyte) file called /usr/lib/chromium/resources.pak – and I suspect that all the non-object-code parts of chromium get somehow baked into it during the build process. Without bothering to find out what file format is being used3, I run strings(1) on it and see if the fully_trusted string is in it:

Bingo! it’s there, and so I search the internet to confirm my hypothesis that resources.pak is a file where all the resources/files for chromium are baked together. Unfortunately, because this is a binary file it is almost certainly full of fields with offset/length information, and fixing those up is a huge pain – I’d rather just find out how to generate it and generate it anew from all the files it contains.

Fortunately, I don’t even need to do this! “fully_trusted”, the string i want to replace, is longer than what I want to replace it with, the string “up_to_date”! This means I can write it over and just pad with spaces4 – remember, we can’t change the length/offset of anything in this file without figuring out how the offsets/sizes work in this file format and fixing them up as appropriate.

Here’s how it looks in our hex editor before we go hands-on:

And how it looks after we set our hex editor’s edit mode to “overwrite” and replaced and padded:

We check that we didn’t mess up the length of the file:

and here’s the diff:

< 001477d8: 7374 6174 7573 223a 2022 6675 6c6c 795f 7472 7573 7465 6422 2c0a 2020 2020 2020 2020 2263 6f6d  status": "fully_trusted",.        "com
> 001477d8: 7374 6174 7573 223a 2022 7570 5f74 6f5f 6461 7465 222c 2020 200a 2020 2020 2020 2020 2263 6f6d  status": "up_to_date",   .        "com
< 00147908: 7573 223a 2022 6675 6c6c 795f 7472 7573 7465 6422 2c0a 2020 2020 2020 2020 2263 6f6d 6d65 6e74  us": "fully_trusted",.        "comment
> 00147908: 7573 223a 2022 7570 5f74 6f5f 6461 7465 222c 2020 200a 2020 2020 2020 2020 2263 6f6d 6d65 6e74  us": "up_to_date",   .        "comment

We replace the original resources.pak with modded .pak and restart chromium, and it works perfectly!

  1. for example, ~4 kilopage datasheets or papers where scatterplots aren’t bitmaps but every dot on the scatterplot is its own PDF object/entity/whatever that needs to be individually rendered and displayed.

  2. This was nontrival because this is chromium version 51 and searching for pretty much anything with “chromium 51” gives you results for chromium-51, a radioactive isotope of chromium used in radiolabeling studies

  3. running file(1) on it just gave me “data”, so it’s probably bespoke

  4. this is a JSON file so padding with spaces doesn’t change what it parses to. If it were a different file format we’d need to use different tricks – for example, if we were editing the text section of an executable, we could pad with NOPs.