I think removing NPAPI support from Google Chrome was a really stupid decision from Google. Sure, Java and some other plugins were buggy and vulnerable. But there is a huge group of users that need to have NPAPI for perfectly legit reasons. Certain banks use NPAPI plugins for 2-factor authentication. Certain countries have made their digital government and signatures based on NPAPI plugins. And the list goes on.
I have my reasons too. If I have to run older version of Chrome for that, I will do so - and no amount of nagging will change my mind.
Thatβs a well known fact in security circles, named "dancing pigs":
If J. Random Websurfer clicks on a button that promises dancing pigs on his computer monitor, and instead gets a hortatory message describing the potential dangers of the applet β he's going to choose dancing pigs over computer security any day
Unfortunately pointy-haired managers at Google fail to understand this simple truth. Or they just don't give a crap.
Hello, I am AutoUpdate, I just broke your computer
Imagine my reaction one day when my NPAPI plugin suddenly stopped working. It just wouldn't load. It turned out that Google Chrome was silently updated by Google Update. It broke my plugin in the process and - officially - there is no way of going back.
What do you think I did next?
That's right - I disabled Google Update from services, patched GoogleUpdate.exe to terminate immediately and restored previous version of Google Chrome from the backup. Dancing pigs, remember?
Your Google Chrome is out-of-date
It worked well for few months. But this week, Chrome started nagging me again.
Quick Google search lead me to this answer: you need to disable Chrome updates using Google's administrative templates.
Let's ignore the fact that the described approach works only for XP (for Windows 7 you need to use ADMX templates which you need to copy manually to %systemroot%\PolicyDefinitions) and now there are like 4 places related to Google Chrome updates in the policies.
So, I set the policies and it seemed to work. For a day.
Your Google Chrome is still out-of-date
Imagine my joy the next day when I saw yet-another-nagscreen. Like this:
No, I don't need that update. Really!
I can close the nag, but 10 minutes later it will pop up again. And it looks like the only way to get rid of the nag is to patch chrome.dll. I really didn't want to do that but dumb decisions by Google managers are forcing my hand here.
Reversing Google Chrome
Since Chrome is more or less open-source, you can easily find the nagware message:
Chrome could not update itself to the latest version, so you are missing out on awesome new features and security fixes. You need to update Chrome.
From here, we can find which dialog is responsible for the nag:
void OutdatedUpgradeBubbleView::Init() {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
accept_button_ = new views::LabelButton(
this, l10n_util::GetStringUTF16(
auto_update_enabled_ ? IDS_REINSTALL_APP : IDS_REENABLE_UPDATES));
accept_button_->SetStyle(views::Button::STYLE_BUTTON);
accept_button_->SetIsDefault(true);
accept_button_->SetFontList(rb.GetFontList(ui::ResourceBundle::BoldFont));
elevation_icon_setter_.reset(new ElevationIconSetter(
accept_button_,
base::Bind(&OutdatedUpgradeBubbleView::SizeToContents,
base::Unretained(this))));
later_button_ = new views::LabelButton(
this, l10n_util::GetStringUTF16(IDS_LATER));
later_button_->SetStyle(views::Button::STYLE_BUTTON);
views::Label* title_label = new views::Label(
l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_TITLE));
title_label->SetFontList(rb.GetFontList(ui::ResourceBundle::MediumFont));
title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
views::Label* text_label = new views::Label(l10n_util::GetStringUTF16(
auto_update_enabled_ ? IDS_UPGRADE_BUBBLE_TEXT
: IDS_UPGRADE_BUBBLE_REENABLE_TEXT));
From there we can find NOTIFICATION_OUTDATED_INSTALL which comes from UpgradeDetector. And finally we arrive at CheckForUpgrade() procedure:
void UpgradeDetectorImpl::CheckForUpgrade() {
// Interrupt any (unlikely) unfinished execution of DetectUpgradeTask, or at
// least prevent the callback from being executed, because we will potentially
// call it from within DetectOutdatedInstall() or will post
// DetectUpgradeTask again below anyway.
weak_factory_.InvalidateWeakPtrs();
// No need to look for upgrades if the install is outdated.
if (DetectOutdatedInstall())
return;
// We use FILE as the thread to run the upgrade detection code on all
// platforms. For Linux, this is because we don't want to block the UI thread
// while launching a background process and reading its output; on the Mac and
// on Windows checking for an upgrade requires reading a file.
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&UpgradeDetectorImpl::DetectUpgradeTask,
weak_factory_.GetWeakPtr()));
}
This is what I want to patch! But how?
You could load Chrome DLL in IDA and try to find the offending call on your own. But I'm willing to bet that it will take you hours, if not days. Well, PDB symbols to the rescue!
Symbols for Chrome are stored at https://chromium-browser-symsrv.commondatastorage.googleapis.com and you will need to add that path to your _NT_SYMBOL_PATH. Something like this:
set _NT_SYMBOL_PATH=SRV*F:\Symbols*https://msdl.microsoft.com/download/symbols;SRV*F:\Symbols*https://chromium-browser-symsrv.commondatastorage.googleapis.com
_NT_SYMBOL_PATH is a very complex beast, you can do all sorts of things with it. If you want a more detailed explanation how it works, I suggest that you read Symbols the Microsoft Way.
After that, you can load chrome.dll in IDA, wait until IDA downloads 850MB of symbols, and drink a coffee or two while IDA is analyzing the file. After that it's all walk in the park. This is the place:
.02CF3BDF: 55 push ebp
.02CF3BE0: 8BEC mov ebp,esp
.02CF3BE2: 83EC20 sub esp,020 ;' '
.02CF3BE5: 8365FC00 and d,[ebp][-4],0
.02CF3BE9: 56 push esi
.02CF3BEA: 8BF1 mov esi,ecx
.02CF3BEC: 57 push edi
.02CF3BED: 8DBE10010000 lea edi,[esi][000000110]
And one retn instruction makes my day so much better..
Final words
Unfortunately for me, this world is changing. You are no more the sole owner of your devices, all the big corporations want to make all the decisions for you.
Luckily for me, it is still possible to achieve a lot using a disassembler and debugger. And reverse engineering for interoperability purposes is completely legal in EU. π
Have fun!