-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
160 lines (130 loc) · 4.79 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
const fs = require("fs");
const path = require('path');
module.exports = inject = require(`./addon/${path.basename(__dirname)}.node`);
function injectBuffer(executable, resourceName, resourceData, options) {
const machoSegmentName = options?.machoSegmentName || "__FIBINJECT";
const sentinelFuse = options?.sentinelFuse || "FIBINJECT_SENTINEL_d0695dd05effa072dcb0b1f8f807ac40";
const subsystem = options?.subsystem || "cui";
if (subsystem !== "cui" && subsystem !== "gui") {
throw new Error("Subsystem must be either 'cui' or 'gui'");
}
if (!Buffer.isBuffer(executable)) {
throw new TypeError("executable must be a buffer");
}
if (!Buffer.isBuffer(resourceData)) {
throw new TypeError("resourceData must be a buffer");
}
const executableFormat = options?.format || inject.get_executable_format(executable);
if (executableFormat === inject.ExecutableFormat.kUnknown) {
throw new Error(
"Executable must be a supported format: ELF, PE, or Mach-O"
);
}
let data;
let result;
switch (executableFormat) {
case inject.ExecutableFormat.kMachO:
{
let sectionName = resourceName;
// Mach-O section names are conventionally of the style __foo
if (!sectionName.startsWith("__")) {
sectionName = `__${sectionName}`;
}
({ result, data } = inject.inject_into_macho(
executable,
machoSegmentName,
sectionName,
resourceData
));
}
break;
case inject.ExecutableFormat.kELF:
{
// ELF sections usually start with a dot ("."), but this is
// technically reserved for the system, so don't transform
let sectionName = resourceName;
({ result, data } = inject.inject_into_elf(
executable,
sectionName,
resourceData
));
}
break;
case inject.ExecutableFormat.kPE:
{
// PE resource names appear to only work if uppercase
resourceName = resourceName.toUpperCase();
({ result, data } = inject.inject_into_pe(
executable,
resourceName,
resourceData,
subsystem === "gui"
));
}
break;
}
if (result !== inject.InjectResult.kSuccess) {
throw new Error("Error when injecting resource");
}
const buffer = Buffer.from(data.buffer);
const checkResource = buffer.indexOf(resourceData);
if (checkResource === -1) {
throw new Error("Resource was not injected correctly");
}
const firstSentinel = buffer.indexOf(sentinelFuse);
if (firstSentinel === -1) {
throw new Error(
`Could not find the sentinel ${sentinelFuse} in the binary`
);
}
const lastSentinel = buffer.lastIndexOf(sentinelFuse);
if (firstSentinel !== lastSentinel) {
throw new Error(
`Multiple occurences of sentinel "${sentinelFuse}" found in the binary`
);
}
const colonIndex = firstSentinel + sentinelFuse.length;
if (buffer[colonIndex] !== ":".charCodeAt(0)) {
throw new Error(
`Value at index ${colonIndex} must be ':' but '${buffer[
colonIndex
].charCodeAt(0)}' was found`
);
}
const hasResourceIndex = firstSentinel + sentinelFuse.length + 1;
const hasResourceValue = buffer[hasResourceIndex];
if (hasResourceValue === "0".charCodeAt(0)) {
buffer[hasResourceIndex] = "1".charCodeAt(0);
} else if (hasResourceValue != "1".charCodeAt(0)) {
throw new Error(
`Value at index ${hasResourceIndex} must be '0' or '1' but '${hasResourceValue.charCodeAt(
0
)}' was found`
);
}
return {
executableFormat,
buffer
};
}
module.exports.injectBuffer = injectBuffer;
module.exports.inject = function (filename, resourceName, resourceData, options) {
try {
fs.accessSync(filename, fs.constants.R_OK | fs.constants.W_OK);
} catch {
throw new Error("Can't read and write to target executable");
}
let executable;
try {
executable = fs.readFileSync(filename);
} catch {
throw new Error("Couldn't read target executable");
}
const { executableFormat, buffer } = injectBuffer(executable, resourceName, resourceData, options);
try {
fs.writeFileSync(filename, buffer);
} catch {
throw new Error("Couldn't write executable");
}
return executableFormat;
}