Slacked: Part 1
Posted on 26th April 2023 at 20:13
My journey into writing a Vencord like client mod for Slack
Contents
How Does Vencord Work?
All electron apps have a resources folder, inside which you’ll find an app.asar. This file contains the apps source code packaged into a single file. There’s nothing special about these files, they’re not encrypted or obfuscated, you can extract the content inside. Electron apps will also load an app.asar directory if extracted, it doesn’t need to be bundled into the archive.
What Vencord does is make a copy of the original asar and replaces the main app.asar with it’s own script. All this script does is load their injector script which is stored elsewhere.
But the patcher is where the magic happens.
Vencord’s Patcher
The first step to understanding this was, how does it actually load Discord? None of the fancy plugins/modding matters if I don’t even know how it eventually opens Discord from its patcher.
I’ve simplified some parts here for clarity.
Interesting! So all it’s doing is replacing require.main!.filename
with the path to Discord’s actual package.json
and loading that at the end! But, does this work for Slack?
Uhhh kinda?
It started! Which is a good sign, the code runs but it seems to exit for some reason.
To debug this, I had to delve into Slack’s minified source code :D
Inside that mess I searched for all process.exit(0)
as the exit code was 0, until I found the culprit!
Inside of main.bundle.js
requestSingleInstanceLock
appears to fail, I suppose this is because technically I am running two instances? My script and then Slack’s actual code? So, let’s replace this part with sed.
It's alive!
This skeleton code now boots into slack via our script! This is where the fun starts.
Opening Chrome Dev Tools on Startup
Let’s start with something simple, how can we trigger the dev tools on startup?
Looking through the rest of Vencord’s patcher, I see that it creates a BrowserWindow
class that extends electron.BrowserWindow
. It only provides an implementation for the constructor and a lot of that isn’t relevant for us right now. The interesting part is this initIpc(this)
function, but we’ll come back to that.
Let’s create our BrowserWindow
class like so.
After which we copy over all of the methods and properties on the original electron.BrowserWindow
to our new window class.
And then we also have to replace electrons BrowserWindow
exports.
That’s it! Surprisingly simple when viewed from our perspective, but I would’ve never figured this out without some serious time and research, so thanks V.
Heading back to that initIpc
function, we passed along our custom BrowserWindow
instance to that function. With electron you can programmatically open devtools from that BrowserWindow
instance, let’s try it.
Annnnnnnnd…
There he is! Mr. Devtools
Wowie, we did it! We can now execute custom code automatically within a Slack desktop client :D
But how does Vencord’s text replacement plugin system work? Can we implement it with our mod? What about loading custom themes? That’s for part 2.