Issue with "Presence of readable code and query in my exe built using electro-packager " #1770
Description
when i create the .exe of my electron project using electron-forage or electron-packager. I get readable content of native node modules embedded in it. I want to obfuscate this code. I know the codes are of native node modules such as chromium, async-hooks, etc in cpp integrated in my app exe, is there a way to get rid of this code by forcing the electron to rely on node-modules folder bundled with app for native node-modules code or is there a way to obfuscate the final .exe file?
Sample code more is there
....\third_party\electron_node\src\node_file.cc
....\third_party\electron_node\src\req_wrap-inl.h:13
env->has_run_bootstrapping_code()
`{node::fs::BindingData
....\third_party\electron_node\src\stream_base-inl.h:23
(req_wrap_obj->GetAlignedPointerFromInternalField( StreamReq::kStreamReqField)) == (nullptr)
SimpleShutdownWrap
FSContinuationData
....\third_party\electron_node\src\env-inl.h:237
FileHandleTransferData
CloseReq
FileHandleReadWrap
BindingData
// Copyright Joyent, Inc. and other Node contributors.
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const {
ArrayPrototypeIncludes,
ArrayPrototypeIndexOf,
ArrayPrototypePop,
ArrayPrototypePush,
ArrayPrototypeShift,
ArrayPrototypeSome,
ArrayPrototypeSplice,
FunctionPrototypeCall,
ObjectCreate,
ObjectKeys,
ObjectSetPrototypeOf,
ObjectValues,
StringPrototypeIndexOf,
StringPrototypeSplit,
StringPrototypeStartsWith,
StringPrototypeSubstr,
Symbol,
} = primordials;
const net = require('net');
const EventEmitter = require('events');
let debug = require('internal/util/debuglog').debuglog('http', (fn) => {
debug = fn;
});
const { AsyncResource } = require('async_hooks');
const { async_id_symbol } = require('internal/async_hooks').symbols;
const {
kEmptyObject,
once,
} = require('internal/util');
const {
validateNumber,
validateOneOf,
validateString,
} = require('internal/validators');
const kOnKeylog = Symbol('onkeylog');
const kRequestOptions = Symbol('requestOptions');
const kRequestAsyncResource = Symbol('requestAsyncResource');
// New Agent code.
// The largest departure from the previous implementation is that
// an Agent instance holds connections for a variable number of host:ports.
// Surprisingly, this is still API compatible as far as third parties are
// concerned. The only code that really notices the difference is the
// request object.
// Another departure is that all code related to HTTP parsing is in
// ClientRequest.onSocket(). The Agent is now strictly
// concerned with managing a connection pool.
class ReusedHandle {
constructor(type, handle) {
this.type = type;
this.handle = handle;
}
function freeSocketErrorListener(err) {
const socket = this;
debug('SOCKET ERROR on FREE socket:', err.message, err.stack);
socket.destroy();
socket.emit('agentRemove');
function Agent(options) {
if (!(this instanceof Agent))
return new Agent(options);
FunctionPrototypeCall(EventEmitter, this);
this.defaultPort = 80;
this.protocol = 'http:';
this.options = { proto: null, ...options };
if (this.options.noDelay === undefined)
this.options.noDelay = true;
// Don't confuse net and make it think that we're connecting to a pipe
this.options.path = null;
this.requests = ObjectCreate(null);
this.sockets = ObjectCreate(null);
this.freeSockets = ObjectCreate(null);
this.keepAliveMsecs = this.options.keepAliveMsecs || 1000;
this.keepAlive = this.options.keepAlive || false;
this.maxSockets = this.options.maxSockets || Agent.defaultMaxSockets;
this.maxFreeSockets = this.options.maxFreeSockets || 256;
this.scheduling = this.options.scheduling || 'lifo';
this.maxTotalSockets = this.options.maxTotalSockets;
this.totalSocketCount = 0;
validateOneOf(this.scheduling, 'scheduling', ['fifo', 'lifo']);
if (this.maxTotalSockets !== undefined) {
validateNumber(this.maxTotalSockets, 'maxTotalSockets', 1);
} else {
this.maxTotalSockets = Infinity;
}
this.on('free', (socket, options) => {
const name = this.getName(options);
debug('agent.on(free)', name);
// TODO(ronag): socket.destroy(err) might have been called
// before coming here and have an 'error' scheduled. In the
// case of socket.destroy() below this 'error' has no handler
// and could cause unhandled exception.
if (!socket.writable) {
socket.destroy();
return;
}
const requests = this.requests[name];
if (requests && requests.length) {
const req = ArrayPrototypeShift(requests);
const reqAsyncRes = req[kRequestAsyncResource];
if (reqAsyncRes) {
// Run request within the original async context.
reqAsyncRes.runInAsyncScope(() => {
asyncResetHandle(socket);
setRequestSocket(this, req, socket);
});
req[kRequestAsyncResource] = null;
} else {
setRequestSocket(this, req, socket);
}
if (requests.length === 0) {
delete this.requests[name];
}
return;
}
// If there are no pending requests, then put it in
// the freeSockets pool, but only if we're allowed to do so.
const req = socket._httpMessage;
if (!req || !req.shouldKeepAlive || !this.keepAlive) {
socket.destroy();
return;
}
const freeSockets = this.freeSockets[name] || [];
const freeLen = freeSockets.length;
let count = freeLen;
if (this.sockets[name])
count += this.sockets[name].length;
if (this.totalSocketCount > this.maxTotalSockets ||
count > this.maxSockets ||
freeLen >= this.maxFreeSockets ||
!this.keepSocketAlive(socket)) {
socket.destroy();
return;
}
this.freeSockets[name] = freeSockets;
socket[async_id_symbol] = -1;
socket._httpMessage = null;
this.removeSocket(socket, options);
socket.once('error', freeSocketErrorListener);
ArrayPrototypePush(freeSockets, socket);
});
// Don't emit keylog events unless there is a listener for them.
this.on('newListener', maybeEnableKeylog);
ObjectSetPrototypeOf(Agent.prototype, EventEmitter.prototype);
ObjectSetPrototypeOf(Agent, EventEmitter);
function maybeEnableKeylog(eventName) {
if (eventName === 'keylog') {
this.removeListener('newListener', maybeEnableKeylog);
// Future sockets will listen on keylog at creation.
const agent = this;
this[kOnKeylog] = function onkeylog(keylog) {
agent.emit('keylog', keylog, this);
};
Sample query more is there
....\storage\browser\file_system\isolated_file_system_backend.cc
Databases
CREATE TABLE Databases (id INTEGER PRIMARY KEY AUTOINCREMENT, origin TEXT NOT NULL, name TEXT NOT NULL, description TEXT NOT NULL, estimated_size INTEGER NOT NULL)
CREATE INDEX origin_index ON Databases (origin)
CREATE UNIQUE INDEX unique_index ON Databases (origin, name)
SELECT id FROM Databases WHERE origin = ? AND name = ?
....\storage\browser\database\databases_table.cc
SELECT description FROM Databases WHERE origin = ? AND name = ?
INSERT INTO Databases (origin, name, description, estimated_size) VALUES (?, ?, ?, 0)
UPDATE Databases SET description = ? WHERE origin = ? AND name = ?
DELETE FROM Databases WHERE origin = ? AND name = ?
SELECT DISTINCT origin FROM Databases ORDER BY origin
I tried obfuscating all the node-modules folder native modules before packaging but code and query in .exe remains. I tried to use .exe obfuscation tool like upx packager but it breaks the app itself. Is there a way to force the electron not to integrate it in .exe and rely on node-modules folder or if it does at least integrate it in obfuscated fashion. As it might make apps build using electron-packager prone to reverse engineering.