First working version of Windows agent icon replacement.

This commit is contained in:
Ylian Saint-Hilaire 2022-08-11 13:34:06 -07:00
parent d2abcdc9d5
commit 37bcae368b
3 changed files with 47 additions and 14 deletions

View File

@ -1268,6 +1268,21 @@ function createAuthenticodeHandler(path) {
return hash.digest();
}
// Hash the file using the selected hashing system skipping resource section
// This hash skips the executables CRC, sections table, resource section, code signing data and signing block
obj.getHashOfSection = function (algo, sectionName) {
if (obj.header.sections[sectionName] == null) return null;
// Get the section start and size
const sectionPtr = obj.header.sections[sectionName].rawAddr;
const sectionSize = obj.header.sections[sectionName].rawSize;
// Hash the remaining data
const hash = crypto.createHash(algo);
runHash(hash, sectionPtr, sectionPtr + sectionSize);
return hash.digest();
}
// Hash the file from start to end loading 64k chunks
function runHash(hash, start, end) {
var ptr = start;

View File

@ -574,7 +574,7 @@
"additionalProperties": false,
"description": "Use this section to set resource metadata of the Windows agents prior to signing. In Windows, you can right-click and select properties to view these values.",
"properties": {
"icon": { "type": "string", "default": null, "description": "DO NOT USE. THIS FEATURE DOES NOT WORK YET. Sets the agent icon, this is the name of a .ico file with the file placed in the meshcentral-data folder." },
"icon": { "type": "string", "description": "Sets the agent icon, this is the name of a .ico file with the file placed in the meshcentral-data folder." },
"fileDescription": { "type": "string", "description": "Executable file description." },
"fileVersion": { "type": "string", "description": "Executable file version, in the form of 'n.n.n.n', for example: '1.2.3.4'." },
"internalName": { "type": "string", "description": "Executable internal name." },

View File

@ -1375,17 +1375,14 @@ function CreateMeshCentralServer(config, args) {
if (icon != null) {
// The icon file was correctly loaded
obj.config.domains[i].agentfileinfo.icon = icon;
obj.config.domains[i].agentfileinfo.iconhash = require('./authenticode.js').hashObject(icon);
} else {
// Failed to load the icon file, display a server warning
addServerWarning("Unable to load agent icon file: " + obj.config.domains[i].agentfileinfo.icon + ".", 23, [obj.config.domains[i].agentfileinfo.icon]);
delete obj.config.domains[i].agentfileinfo.icon;
delete obj.config.domains[i].agentfileinfo.iconhash;
}
} else {
// Invalid icon file path
delete obj.config.domains[i].agentfileinfo.icon;
delete obj.config.domains[i].agentfileinfo.iconhash;
}
}
}
@ -2995,21 +2992,42 @@ function CreateMeshCentralServer(config, args) {
}
// Check the agent icon
if ((destinationAgentOk == true) && (domain.agentfileinfo != null) && (domain.agentfileinfo.iconhash != null)) {
const agentIconGroups = destinationAgent.getIconInfo();
if (agentIconGroups != null) {
const agentIconGroupNames = Object.keys(agentIconGroups);
if (agentIconGroupNames.length > 0) {
const agentMainIconGroupName = agentIconGroupNames[0];
const agentMainIconGroupHash = require('./authenticode.js').hashObject(agentIconGroups[agentMainIconGroupName]);
if (agentMainIconGroupHash != domain.agentfileinfo.iconhash) { destinationAgentOk = false; } // If the existing agent icon does not match the desired icon, we need to re-sign the agent.
if (destinationAgentOk == true) {
if ((domain.agentfileinfo != null) && (domain.agentfileinfo.icon != null)) {
// Check if the destination agent matches the icon we want
const agentIconGroups = destinationAgent.getIconInfo();
if (agentIconGroups != null) {
const agentIconGroupNames = Object.keys(agentIconGroups);
if (agentIconGroupNames.length > 0) {
const agentMainIconGroup = agentIconGroups[agentIconGroupNames[0]];
if (agentMainIconGroup.resCount != domain.agentfileinfo.icon.resCount) {
destinationAgentOk = false; // The icon image count is different, don't bother hashing to see if the icons are different.
} else {
const agentMainIconGroupHash = require('./authenticode.js').hashObject(agentMainIconGroup);
const iconHash = require('./authenticode.js').hashObject(domain.agentfileinfo.icon);
if (agentMainIconGroupHash != iconHash) { destinationAgentOk = false; } // If the existing agent icon does not match the desired icon, we need to re-sign the agent.
}
}
}
} else {
// Check if the destination agent has the default icon
const agentIconGroups1 = destinationAgent.getIconInfo();
const agentIconGroups2 = originalAgent.getIconInfo();
if (agentIconGroups1.resCount != agentIconGroups2.resCount) {
destinationAgentOk = false; // The icon image count is different, don't bother hashing to see if the icons are different.
} else {
const iconHash1 = require('./authenticode.js').hashObject(agentIconGroups1);
const iconHash2 = require('./authenticode.js').hashObject(agentIconGroups2);
if (iconHash1 != iconHash2) { destinationAgentOk = false; } // If the existing agent icon does not match the desired icon, we need to re-sign the agent.
}
}
}
}
// If everything looks ok, runs a hash of the original and destination agent skipping the CRC, resource and signature blocks. If different, sign the agent again.
if ((destinationAgentOk == true) && (originalAgent.getHashNoResources('sha384').compare(destinationAgent.getHashNoResources('sha384')) != 0)) { destinationAgentOk = false; }
// If everything looks ok, runs a hash of the original and destination agent .text, .data and .rdata sections. If different, sign the agent again.
if ((destinationAgentOk == true) && (originalAgent.getHashOfSection('sha384', '.text').compare(destinationAgent.getHashOfSection('sha384', '.text')) != 0)) { destinationAgentOk = false; }
if ((destinationAgentOk == true) && (originalAgent.getHashOfSection('sha384', '.data').compare(destinationAgent.getHashOfSection('sha384', '.data')) != 0)) { destinationAgentOk = false; }
if ((destinationAgentOk == true) && (originalAgent.getHashOfSection('sha384', '.rdata').compare(destinationAgent.getHashOfSection('sha384', '.rdata')) != 0)) { destinationAgentOk = false; }
// We are done comparing the destination agent, close it.
destinationAgent.close();