cyberchef 10.22.1 → 10.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +131 -0
- package/CONTRIBUTING.md +37 -0
- package/Dockerfile +2 -0
- package/Gruntfile.js +0 -12
- package/README.md +1 -1
- package/babel.config.js +0 -6
- package/package.json +63 -62
- package/src/core/Chef.mjs +8 -1
- package/src/core/Ingredient.mjs +5 -2
- package/src/core/Operation.mjs +6 -1
- package/src/core/Recipe.mjs +10 -5
- package/src/core/config/Categories.json +18 -3
- package/src/core/config/OperationConfig.json +496 -23
- package/src/core/config/modules/Ciphers.mjs +6 -0
- package/src/core/config/modules/Crypto.mjs +6 -0
- package/src/core/config/modules/Default.mjs +6 -0
- package/src/core/config/modules/Shellcode.mjs +2 -0
- package/src/core/lib/AudioBytes.mjs +103 -0
- package/src/core/lib/AudioMetaSchema.mjs +82 -0
- package/src/core/lib/AudioParsers.mjs +630 -0
- package/src/core/lib/BigIntUtils.mjs +73 -0
- package/src/core/lib/Modhex.mjs +2 -0
- package/src/core/lib/QRCode.mjs +30 -10
- package/src/core/lib/RC6.mjs +625 -0
- package/src/core/operations/A1Z26CipherDecode.mjs +1 -1
- package/src/core/operations/AddTextToImage.mjs +116 -64
- package/src/core/operations/BlurImage.mjs +10 -12
- package/src/core/operations/ContainImage.mjs +50 -40
- package/src/core/operations/ConvertImageFormat.mjs +33 -39
- package/src/core/operations/CoverImage.mjs +39 -37
- package/src/core/operations/CropImage.mjs +35 -21
- package/src/core/operations/DisassembleARM.mjs +193 -0
- package/src/core/operations/DitherImage.mjs +8 -8
- package/src/core/operations/EscapeUnicodeCharacters.mjs +0 -17
- package/src/core/operations/ExtractAudioMetadata.mjs +175 -0
- package/src/core/operations/ExtractLSB.mjs +17 -11
- package/src/core/operations/ExtractRGBA.mjs +12 -10
- package/src/core/operations/FlaskSessionDecode.mjs +80 -0
- package/src/core/operations/FlaskSessionSign.mjs +89 -0
- package/src/core/operations/FlaskSessionVerify.mjs +136 -0
- package/src/core/operations/FlipImage.mjs +14 -10
- package/src/core/operations/GenerateImage.mjs +39 -32
- package/src/core/operations/ImageBrightnessContrast.mjs +10 -10
- package/src/core/operations/ImageFilter.mjs +14 -13
- package/src/core/operations/ImageHueSaturationLightness.mjs +22 -20
- package/src/core/operations/ImageOpacity.mjs +6 -8
- package/src/core/operations/InvertImage.mjs +4 -6
- package/src/core/operations/Jq.mjs +12 -4
- package/src/core/operations/NormaliseImage.mjs +5 -7
- package/src/core/operations/OffsetChecker.mjs +1 -1
- package/src/core/operations/ParseEthernetFrame.mjs +112 -0
- package/src/core/operations/ParseIPv4Header.mjs +23 -6
- package/src/core/operations/ParseQRCode.mjs +13 -13
- package/src/core/operations/PseudoRandomIntegerGenerator.mjs +164 -0
- package/src/core/operations/RC6Decrypt.mjs +119 -0
- package/src/core/operations/RC6Encrypt.mjs +119 -0
- package/src/core/operations/RandomizeColourPalette.mjs +11 -11
- package/src/core/operations/ResizeImage.mjs +30 -23
- package/src/core/operations/RotateImage.mjs +8 -9
- package/src/core/operations/SQLBeautify.mjs +21 -3
- package/src/core/operations/SharpenImage.mjs +94 -62
- package/src/core/operations/SplitColourChannels.mjs +47 -21
- package/src/core/operations/TextIntegerConverter.mjs +123 -0
- package/src/core/operations/UnescapeUnicodeCharacters.mjs +17 -0
- package/src/core/operations/ViewBitPlane.mjs +16 -20
- package/src/core/operations/index.mjs +20 -0
- package/src/node/index.mjs +50 -0
- package/src/web/HTMLIngredient.mjs +24 -43
- package/src/web/Manager.mjs +1 -0
- package/src/web/html/index.html +6 -6
- package/src/web/static/fonts/bmfonts/Roboto72White.fnt +491 -485
- package/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt +494 -488
- package/src/web/static/fonts/bmfonts/RobotoMono72White.fnt +110 -103
- package/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt +498 -492
- package/src/web/stylesheets/layout/_banner.css +30 -0
- package/src/web/stylesheets/layout/_modals.css +5 -0
- package/src/web/stylesheets/utils/_overrides.css +7 -0
- package/src/web/waiters/ControlsWaiter.mjs +82 -0
- package/src/web/waiters/InputWaiter.mjs +12 -6
- package/src/web/waiters/RecipeWaiter.mjs +2 -2
- package/tests/browser/02_ops.js +23 -3
- package/tests/node/index.mjs +1 -0
- package/tests/node/tests/lib/BigIntUtils.mjs +150 -0
- package/tests/node/tests/operations.mjs +9 -7
- package/tests/operations/index.mjs +8 -0
- package/tests/operations/tests/A1Z26CipherDecode.mjs +33 -0
- package/tests/operations/tests/DisassembleARM.mjs +377 -0
- package/tests/operations/tests/ExtractAudioMetadata.mjs +287 -0
- package/tests/operations/tests/FlaskSession.mjs +246 -0
- package/tests/operations/tests/GenerateQRCode.mjs +67 -0
- package/tests/operations/tests/JWTSign.mjs +83 -8
- package/tests/operations/tests/Jq.mjs +32 -0
- package/tests/operations/tests/Modhex.mjs +20 -0
- package/tests/operations/tests/ParseEthernetFrame.mjs +45 -0
- package/tests/operations/tests/RC6.mjs +487 -0
- package/tests/operations/tests/SQLBeautify.mjs +54 -0
- package/tests/operations/tests/TextIntegerConverter.mjs +199 -0
- package/tests/samples/Audio.mjs +73 -0
- package/tests/samples/Images.mjs +0 -12
- package/webpack.config.js +10 -7
- package/src/core/lib/ImageManipulation.mjs +0 -251
|
@@ -8,13 +8,12 @@ import Operation from "../Operation.mjs";
|
|
|
8
8
|
import OperationError from "../errors/OperationError.mjs";
|
|
9
9
|
import { isImage } from "../lib/FileType.mjs";
|
|
10
10
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
11
|
-
import Jimp from "jimp
|
|
11
|
+
import { Jimp, JimpMime, PNGFilterType } from "jimp";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Convert Image Format operation
|
|
15
15
|
*/
|
|
16
16
|
class ConvertImageFormat extends Operation {
|
|
17
|
-
|
|
18
17
|
/**
|
|
19
18
|
* ConvertImageFormat constructor
|
|
20
19
|
*/
|
|
@@ -23,7 +22,8 @@ class ConvertImageFormat extends Operation {
|
|
|
23
22
|
|
|
24
23
|
this.name = "Convert Image Format";
|
|
25
24
|
this.module = "Image";
|
|
26
|
-
this.description =
|
|
25
|
+
this.description =
|
|
26
|
+
"Converts an image between different formats. Supported formats:<br><ul><li>Joint Photographic Experts Group (JPEG)</li><li>Portable Network Graphics (PNG)</li><li>Bitmap (BMP)</li><li>Tagged Image File Format (TIFF)</li></ul><br>Note: GIF files are supported for input, but cannot be outputted.";
|
|
27
27
|
this.infoURL = "https://wikipedia.org/wiki/Image_file_formats";
|
|
28
28
|
this.inputType = "ArrayBuffer";
|
|
29
29
|
this.outputType = "ArrayBuffer";
|
|
@@ -32,39 +32,27 @@ class ConvertImageFormat extends Operation {
|
|
|
32
32
|
{
|
|
33
33
|
name: "Output Format",
|
|
34
34
|
type: "option",
|
|
35
|
-
value: [
|
|
36
|
-
"JPEG",
|
|
37
|
-
"PNG",
|
|
38
|
-
"BMP",
|
|
39
|
-
"TIFF"
|
|
40
|
-
]
|
|
35
|
+
value: ["JPEG", "PNG", "BMP", "TIFF"],
|
|
41
36
|
},
|
|
42
37
|
{
|
|
43
38
|
name: "JPEG Quality",
|
|
44
39
|
type: "number",
|
|
45
40
|
value: 80,
|
|
46
41
|
min: 1,
|
|
47
|
-
max: 100
|
|
42
|
+
max: 100,
|
|
48
43
|
},
|
|
49
44
|
{
|
|
50
45
|
name: "PNG Filter Type",
|
|
51
46
|
type: "option",
|
|
52
|
-
value: [
|
|
53
|
-
"Auto",
|
|
54
|
-
"None",
|
|
55
|
-
"Sub",
|
|
56
|
-
"Up",
|
|
57
|
-
"Average",
|
|
58
|
-
"Paeth"
|
|
59
|
-
]
|
|
47
|
+
value: ["Auto", "None", "Sub", "Up", "Average", "Paeth"],
|
|
60
48
|
},
|
|
61
49
|
{
|
|
62
50
|
name: "PNG Deflate Level",
|
|
63
51
|
type: "number",
|
|
64
52
|
value: 9,
|
|
65
53
|
min: 0,
|
|
66
|
-
max: 9
|
|
67
|
-
}
|
|
54
|
+
max: 9,
|
|
55
|
+
},
|
|
68
56
|
];
|
|
69
57
|
}
|
|
70
58
|
|
|
@@ -76,19 +64,19 @@ class ConvertImageFormat extends Operation {
|
|
|
76
64
|
async run(input, args) {
|
|
77
65
|
const [format, jpegQuality, pngFilterType, pngDeflateLevel] = args;
|
|
78
66
|
const formatMap = {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
67
|
+
JPEG: JimpMime.jpeg,
|
|
68
|
+
PNG: JimpMime.png,
|
|
69
|
+
BMP: JimpMime.bmp,
|
|
70
|
+
TIFF: JimpMime.tiff,
|
|
83
71
|
};
|
|
84
72
|
|
|
85
73
|
const pngFilterMap = {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
74
|
+
Auto: PNGFilterType.AUTO,
|
|
75
|
+
None: PNGFilterType.NONE,
|
|
76
|
+
Sub: PNGFilterType.SUB,
|
|
77
|
+
Up: PNGFilterType.UP,
|
|
78
|
+
Average: PNGFilterType.AVERAGE,
|
|
79
|
+
Paeth: PNGFilterType.PATH,
|
|
92
80
|
};
|
|
93
81
|
|
|
94
82
|
const mime = formatMap[format];
|
|
@@ -103,18 +91,25 @@ class ConvertImageFormat extends Operation {
|
|
|
103
91
|
throw new OperationError(`Error opening image file. (${err})`);
|
|
104
92
|
}
|
|
105
93
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
94
|
+
let buffer;
|
|
95
|
+
switch (mime) {
|
|
96
|
+
case JimpMime.jpeg:
|
|
97
|
+
buffer = await image.getBuffer(mime, {
|
|
98
|
+
quality: jpegQuality,
|
|
99
|
+
});
|
|
109
100
|
break;
|
|
110
|
-
case
|
|
111
|
-
image.
|
|
112
|
-
|
|
101
|
+
case JimpMime.png:
|
|
102
|
+
buffer = await image.getBuffer(mime, {
|
|
103
|
+
filterType: pngFilterMap[pngFilterType],
|
|
104
|
+
deflateLevel: pngDeflateLevel,
|
|
105
|
+
});
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
buffer = await image.getBuffer(mime);
|
|
113
109
|
break;
|
|
114
110
|
}
|
|
115
111
|
|
|
116
|
-
|
|
117
|
-
return imageBuffer.buffer;
|
|
112
|
+
return buffer.buffer;
|
|
118
113
|
} catch (err) {
|
|
119
114
|
throw new OperationError(`Error converting image format. (${err})`);
|
|
120
115
|
}
|
|
@@ -137,7 +132,6 @@ class ConvertImageFormat extends Operation {
|
|
|
137
132
|
|
|
138
133
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
139
134
|
}
|
|
140
|
-
|
|
141
135
|
}
|
|
142
136
|
|
|
143
137
|
export default ConvertImageFormat;
|
|
@@ -9,13 +9,18 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
9
9
|
import { isImage } from "../lib/FileType.mjs";
|
|
10
10
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
11
11
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
|
12
|
-
import
|
|
12
|
+
import {
|
|
13
|
+
Jimp,
|
|
14
|
+
JimpMime,
|
|
15
|
+
ResizeStrategy,
|
|
16
|
+
HorizontalAlign,
|
|
17
|
+
VerticalAlign,
|
|
18
|
+
} from "jimp";
|
|
13
19
|
|
|
14
20
|
/**
|
|
15
21
|
* Cover Image operation
|
|
16
22
|
*/
|
|
17
23
|
class CoverImage extends Operation {
|
|
18
|
-
|
|
19
24
|
/**
|
|
20
25
|
* CoverImage constructor
|
|
21
26
|
*/
|
|
@@ -24,7 +29,8 @@ class CoverImage extends Operation {
|
|
|
24
29
|
|
|
25
30
|
this.name = "Cover Image";
|
|
26
31
|
this.module = "Image";
|
|
27
|
-
this.description =
|
|
32
|
+
this.description =
|
|
33
|
+
"Scales the image to the given width and height, keeping the aspect ratio. The image may be clipped.";
|
|
28
34
|
this.infoURL = "";
|
|
29
35
|
this.inputType = "ArrayBuffer";
|
|
30
36
|
this.outputType = "ArrayBuffer";
|
|
@@ -34,33 +40,25 @@ class CoverImage extends Operation {
|
|
|
34
40
|
name: "Width",
|
|
35
41
|
type: "number",
|
|
36
42
|
value: 100,
|
|
37
|
-
min: 1
|
|
43
|
+
min: 1,
|
|
38
44
|
},
|
|
39
45
|
{
|
|
40
46
|
name: "Height",
|
|
41
47
|
type: "number",
|
|
42
48
|
value: 100,
|
|
43
|
-
min: 1
|
|
49
|
+
min: 1,
|
|
44
50
|
},
|
|
45
51
|
{
|
|
46
52
|
name: "Horizontal align",
|
|
47
53
|
type: "option",
|
|
48
|
-
value: [
|
|
49
|
-
|
|
50
|
-
"Center",
|
|
51
|
-
"Right"
|
|
52
|
-
],
|
|
53
|
-
defaultIndex: 1
|
|
54
|
+
value: ["Left", "Center", "Right"],
|
|
55
|
+
defaultIndex: 1,
|
|
54
56
|
},
|
|
55
57
|
{
|
|
56
58
|
name: "Vertical align",
|
|
57
59
|
type: "option",
|
|
58
|
-
value: [
|
|
59
|
-
|
|
60
|
-
"Middle",
|
|
61
|
-
"Bottom"
|
|
62
|
-
],
|
|
63
|
-
defaultIndex: 1
|
|
60
|
+
value: ["Top", "Middle", "Bottom"],
|
|
61
|
+
defaultIndex: 1,
|
|
64
62
|
},
|
|
65
63
|
{
|
|
66
64
|
name: "Resizing algorithm",
|
|
@@ -70,10 +68,10 @@ class CoverImage extends Operation {
|
|
|
70
68
|
"Bilinear",
|
|
71
69
|
"Bicubic",
|
|
72
70
|
"Hermite",
|
|
73
|
-
"Bezier"
|
|
71
|
+
"Bezier",
|
|
74
72
|
],
|
|
75
|
-
defaultIndex: 1
|
|
76
|
-
}
|
|
73
|
+
defaultIndex: 1,
|
|
74
|
+
},
|
|
77
75
|
];
|
|
78
76
|
}
|
|
79
77
|
|
|
@@ -86,20 +84,20 @@ class CoverImage extends Operation {
|
|
|
86
84
|
const [width, height, hAlign, vAlign, alg] = args;
|
|
87
85
|
|
|
88
86
|
const resizeMap = {
|
|
89
|
-
"Nearest Neighbour":
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
"Nearest Neighbour": ResizeStrategy.NEAREST_NEIGHBOR,
|
|
88
|
+
Bilinear: ResizeStrategy.BILINEAR,
|
|
89
|
+
Bicubic: ResizeStrategy.BICUBIC,
|
|
90
|
+
Hermite: ResizeStrategy.HERMITE,
|
|
91
|
+
Bezier: ResizeStrategy.BEZIER,
|
|
94
92
|
};
|
|
95
93
|
|
|
96
94
|
const alignMap = {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
95
|
+
Left: HorizontalAlign.LEFT,
|
|
96
|
+
Center: HorizontalAlign.CENTER,
|
|
97
|
+
Right: HorizontalAlign.RIGHT,
|
|
98
|
+
Top: VerticalAlign.TOP,
|
|
99
|
+
Middle: VerticalAlign.MIDDLE,
|
|
100
|
+
Bottom: VerticalAlign.BOTTOM,
|
|
103
101
|
};
|
|
104
102
|
|
|
105
103
|
if (!isImage(input)) {
|
|
@@ -108,19 +106,24 @@ class CoverImage extends Operation {
|
|
|
108
106
|
|
|
109
107
|
let image;
|
|
110
108
|
try {
|
|
111
|
-
image = await
|
|
109
|
+
image = await Jimp.read(input);
|
|
112
110
|
} catch (err) {
|
|
113
111
|
throw new OperationError(`Error loading image. (${err})`);
|
|
114
112
|
}
|
|
115
113
|
try {
|
|
116
114
|
if (isWorkerEnvironment())
|
|
117
115
|
self.sendStatusMessage("Covering image...");
|
|
118
|
-
image.cover(
|
|
116
|
+
image.cover({
|
|
117
|
+
w: width,
|
|
118
|
+
h: height,
|
|
119
|
+
align: alignMap[hAlign] | alignMap[vAlign],
|
|
120
|
+
mode: resizeMap[alg],
|
|
121
|
+
});
|
|
119
122
|
let imageBuffer;
|
|
120
|
-
if (image.
|
|
121
|
-
imageBuffer = await image.
|
|
123
|
+
if (image.mime === "image/gif") {
|
|
124
|
+
imageBuffer = await image.getBuffer(JimpMime.png);
|
|
122
125
|
} else {
|
|
123
|
-
imageBuffer = await image.
|
|
126
|
+
imageBuffer = await image.getBuffer(image.mime);
|
|
124
127
|
}
|
|
125
128
|
return imageBuffer.buffer;
|
|
126
129
|
} catch (err) {
|
|
@@ -144,7 +147,6 @@ class CoverImage extends Operation {
|
|
|
144
147
|
|
|
145
148
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
146
149
|
}
|
|
147
|
-
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
export default CoverImage;
|
|
@@ -9,13 +9,12 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
9
9
|
import { isImage } from "../lib/FileType.mjs";
|
|
10
10
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
11
11
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
|
12
|
-
import Jimp from "jimp
|
|
12
|
+
import { Jimp, JimpMime } from "jimp";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Crop Image operation
|
|
16
16
|
*/
|
|
17
17
|
class CropImage extends Operation {
|
|
18
|
-
|
|
19
18
|
/**
|
|
20
19
|
* CropImage constructor
|
|
21
20
|
*/
|
|
@@ -24,7 +23,8 @@ class CropImage extends Operation {
|
|
|
24
23
|
|
|
25
24
|
this.name = "Crop Image";
|
|
26
25
|
this.module = "Image";
|
|
27
|
-
this.description =
|
|
26
|
+
this.description =
|
|
27
|
+
"Crops an image to the specified region, or automatically crops edges.<br><br><b><u>Autocrop</u></b><br>Automatically crops same-colour borders from the image.<br><br><u>Autocrop tolerance</u><br>A percentage value for the tolerance of colour difference between pixels.<br><br><u>Only autocrop frames</u><br>Only crop real frames (all sides must have the same border)<br><br><u>Symmetric autocrop</u><br>Force autocrop to be symmetric (top/bottom and left/right are cropped by the same amount)<br><br><u>Autocrop keep border</u><br>The number of pixels of border to leave around the image.";
|
|
28
28
|
this.infoURL = "https://wikipedia.org/wiki/Cropping_(image)";
|
|
29
29
|
this.inputType = "ArrayBuffer";
|
|
30
30
|
this.outputType = "ArrayBuffer";
|
|
@@ -34,30 +34,30 @@ class CropImage extends Operation {
|
|
|
34
34
|
name: "X Position",
|
|
35
35
|
type: "number",
|
|
36
36
|
value: 0,
|
|
37
|
-
min: 0
|
|
37
|
+
min: 0,
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
name: "Y Position",
|
|
41
41
|
type: "number",
|
|
42
42
|
value: 0,
|
|
43
|
-
min: 0
|
|
43
|
+
min: 0,
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
name: "Width",
|
|
47
47
|
type: "number",
|
|
48
48
|
value: 10,
|
|
49
|
-
min: 1
|
|
49
|
+
min: 1,
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
name: "Height",
|
|
53
53
|
type: "number",
|
|
54
54
|
value: 10,
|
|
55
|
-
min: 1
|
|
55
|
+
min: 1,
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
name: "Autocrop",
|
|
59
59
|
type: "boolean",
|
|
60
|
-
value: false
|
|
60
|
+
value: false,
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
name: "Autocrop tolerance (%)",
|
|
@@ -65,24 +65,24 @@ class CropImage extends Operation {
|
|
|
65
65
|
value: 0.02,
|
|
66
66
|
min: 0,
|
|
67
67
|
max: 100,
|
|
68
|
-
step: 0.01
|
|
68
|
+
step: 0.01,
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
name: "Only autocrop frames",
|
|
72
72
|
type: "boolean",
|
|
73
|
-
value: true
|
|
73
|
+
value: true,
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
name: "Symmetric autocrop",
|
|
77
77
|
type: "boolean",
|
|
78
|
-
value: false
|
|
78
|
+
value: false,
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
name: "Autocrop keep border (px)",
|
|
82
82
|
type: "number",
|
|
83
83
|
value: 0,
|
|
84
|
-
min: 0
|
|
85
|
-
}
|
|
84
|
+
min: 0,
|
|
85
|
+
},
|
|
86
86
|
];
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -92,7 +92,17 @@ class CropImage extends Operation {
|
|
|
92
92
|
* @returns {byteArray}
|
|
93
93
|
*/
|
|
94
94
|
async run(input, args) {
|
|
95
|
-
const [
|
|
95
|
+
const [
|
|
96
|
+
xPos,
|
|
97
|
+
yPos,
|
|
98
|
+
width,
|
|
99
|
+
height,
|
|
100
|
+
autocrop,
|
|
101
|
+
autoTolerance,
|
|
102
|
+
autoFrames,
|
|
103
|
+
autoSymmetric,
|
|
104
|
+
autoBorder,
|
|
105
|
+
] = args;
|
|
96
106
|
if (!isImage(input)) {
|
|
97
107
|
throw new OperationError("Invalid file type.");
|
|
98
108
|
}
|
|
@@ -108,20 +118,25 @@ class CropImage extends Operation {
|
|
|
108
118
|
self.sendStatusMessage("Cropping image...");
|
|
109
119
|
if (autocrop) {
|
|
110
120
|
image.autocrop({
|
|
111
|
-
tolerance:
|
|
121
|
+
tolerance: autoTolerance / 100,
|
|
112
122
|
cropOnlyFrames: autoFrames,
|
|
113
123
|
cropSymmetric: autoSymmetric,
|
|
114
|
-
leaveBorder: autoBorder
|
|
124
|
+
leaveBorder: autoBorder,
|
|
115
125
|
});
|
|
116
126
|
} else {
|
|
117
|
-
image.crop(
|
|
127
|
+
image.crop({
|
|
128
|
+
x: xPos,
|
|
129
|
+
y: yPos,
|
|
130
|
+
w: width,
|
|
131
|
+
h: height,
|
|
132
|
+
});
|
|
118
133
|
}
|
|
119
134
|
|
|
120
135
|
let imageBuffer;
|
|
121
|
-
if (image.
|
|
122
|
-
imageBuffer = await image.
|
|
136
|
+
if (image.mime === "image/gif") {
|
|
137
|
+
imageBuffer = await image.getBuffer(JimpMime.png);
|
|
123
138
|
} else {
|
|
124
|
-
imageBuffer = await image.
|
|
139
|
+
imageBuffer = await image.getBuffer(image.mime);
|
|
125
140
|
}
|
|
126
141
|
return imageBuffer.buffer;
|
|
127
142
|
} catch (err) {
|
|
@@ -145,7 +160,6 @@ class CropImage extends Operation {
|
|
|
145
160
|
|
|
146
161
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
147
162
|
}
|
|
148
|
-
|
|
149
163
|
}
|
|
150
164
|
|
|
151
165
|
export default CropImage;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author MedjedThomasXM
|
|
3
|
+
* @copyright Crown Copyright 2024
|
|
4
|
+
* @license Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import Operation from "../Operation.mjs";
|
|
8
|
+
import OperationError from "../errors/OperationError.mjs";
|
|
9
|
+
import { isWorkerEnvironment } from "../Utils.mjs";
|
|
10
|
+
import cs from "@alexaltea/capstone-js/dist/capstone.min.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Disassemble ARM operation
|
|
14
|
+
*/
|
|
15
|
+
class DisassembleARM extends Operation {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* DisassembleARM constructor
|
|
19
|
+
*/
|
|
20
|
+
constructor() {
|
|
21
|
+
super();
|
|
22
|
+
|
|
23
|
+
this.name = "Disassemble ARM";
|
|
24
|
+
this.module = "Shellcode";
|
|
25
|
+
this.description = "Disassembles ARM machine code into assembly language.<br><br>Supports ARM (32-bit), Thumb, and ARM64 (AArch64) architectures using the Capstone disassembly framework.<br><br>Input should be in hexadecimal.";
|
|
26
|
+
this.infoURL = "https://wikipedia.org/wiki/ARM_architecture_family";
|
|
27
|
+
this.inputType = "string";
|
|
28
|
+
this.outputType = "string";
|
|
29
|
+
this.args = [
|
|
30
|
+
{
|
|
31
|
+
"name": "Architecture",
|
|
32
|
+
"type": "option",
|
|
33
|
+
"value": ["ARM (32-bit)", "ARM64 (AArch64)"]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "Mode",
|
|
37
|
+
"type": "option",
|
|
38
|
+
"value": ["ARM", "Thumb", "Thumb + Cortex-M", "ARMv8"]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "Endianness",
|
|
42
|
+
"type": "option",
|
|
43
|
+
"value": ["Little Endian", "Big Endian"]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "Starting address (hex)",
|
|
47
|
+
"type": "number",
|
|
48
|
+
"value": 0
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "Show instruction hex",
|
|
52
|
+
"type": "boolean",
|
|
53
|
+
"value": true
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "Show instruction position",
|
|
57
|
+
"type": "boolean",
|
|
58
|
+
"value": true
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {string} input
|
|
65
|
+
* @param {Object[]} args
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
async run(input, args) {
|
|
69
|
+
const [
|
|
70
|
+
architecture,
|
|
71
|
+
mode,
|
|
72
|
+
endianness,
|
|
73
|
+
startAddress,
|
|
74
|
+
showHex,
|
|
75
|
+
showPosition
|
|
76
|
+
] = args;
|
|
77
|
+
|
|
78
|
+
// Remove whitespace from input
|
|
79
|
+
const hexInput = input.replace(/\s/g, "");
|
|
80
|
+
|
|
81
|
+
// Validate hex input
|
|
82
|
+
if (!/^[0-9a-fA-F]*$/.test(hexInput)) {
|
|
83
|
+
throw new OperationError("Invalid hexadecimal input. Please provide valid hex characters only.");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (hexInput.length === 0) {
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (hexInput.length % 2 !== 0) {
|
|
91
|
+
throw new OperationError("Invalid hexadecimal input. Length must be even.");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Convert hex string to byte array
|
|
95
|
+
const bytes = [];
|
|
96
|
+
for (let i = 0; i < hexInput.length; i += 2) {
|
|
97
|
+
bytes.push(parseInt(hexInput.substr(i, 2), 16));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Determine architecture constant
|
|
101
|
+
let arch;
|
|
102
|
+
if (architecture === "ARM64 (AArch64)") {
|
|
103
|
+
arch = cs.ARCH_ARM64;
|
|
104
|
+
} else {
|
|
105
|
+
arch = cs.ARCH_ARM;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Determine mode constant
|
|
109
|
+
let modeValue = cs.MODE_LITTLE_ENDIAN;
|
|
110
|
+
|
|
111
|
+
if (architecture === "ARM (32-bit)") {
|
|
112
|
+
switch (mode) {
|
|
113
|
+
case "ARM":
|
|
114
|
+
modeValue = cs.MODE_ARM;
|
|
115
|
+
break;
|
|
116
|
+
case "Thumb":
|
|
117
|
+
modeValue = cs.MODE_THUMB;
|
|
118
|
+
break;
|
|
119
|
+
case "Thumb + Cortex-M":
|
|
120
|
+
modeValue = cs.MODE_THUMB | cs.MODE_MCLASS;
|
|
121
|
+
break;
|
|
122
|
+
case "ARMv8":
|
|
123
|
+
modeValue = cs.MODE_ARM | cs.MODE_V8;
|
|
124
|
+
break;
|
|
125
|
+
default:
|
|
126
|
+
modeValue = cs.MODE_ARM;
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
// ARM64 only has one mode (ARM mode is default for ARM64)
|
|
130
|
+
modeValue = cs.MODE_ARM;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Add endianness
|
|
134
|
+
if (endianness === "Big Endian") {
|
|
135
|
+
modeValue |= cs.MODE_BIG_ENDIAN;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (isWorkerEnvironment()) {
|
|
139
|
+
self.sendStatusMessage("Disassembling...");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let disassembler;
|
|
143
|
+
try {
|
|
144
|
+
disassembler = new cs.Capstone(arch, modeValue);
|
|
145
|
+
} catch (e) {
|
|
146
|
+
throw new OperationError(`Failed to initialise Capstone disassembler: ${e}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let instructions;
|
|
150
|
+
try {
|
|
151
|
+
instructions = disassembler.disasm(bytes, startAddress);
|
|
152
|
+
} catch (e) {
|
|
153
|
+
disassembler.close();
|
|
154
|
+
// Check if it's a "no valid instructions" error (code 0 means OK but nothing decoded)
|
|
155
|
+
if (e && e.includes && e.includes("code 0:")) {
|
|
156
|
+
throw new OperationError(`No valid ${architecture} instructions found in input. The bytes may be for a different architecture or mode.`);
|
|
157
|
+
}
|
|
158
|
+
throw new OperationError(`Disassembly failed: ${e}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Format output
|
|
162
|
+
const output = [];
|
|
163
|
+
for (const insn of instructions) {
|
|
164
|
+
let line = "";
|
|
165
|
+
|
|
166
|
+
if (showPosition) {
|
|
167
|
+
// Format address as hex with 0x prefix
|
|
168
|
+
const addrHex = "0x" + insn.address.toString(16).padStart(8, "0");
|
|
169
|
+
line += addrHex + " ";
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (showHex) {
|
|
173
|
+
// Format instruction bytes as hex
|
|
174
|
+
const bytesHex = insn.bytes.map(b => b.toString(16).padStart(2, "0")).join("");
|
|
175
|
+
line += bytesHex.padEnd(16, " ") + " ";
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
line += insn.mnemonic;
|
|
179
|
+
if (insn.op_str) {
|
|
180
|
+
line += " " + insn.op_str;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
output.push(line);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
disassembler.close();
|
|
187
|
+
|
|
188
|
+
return output.join("\n");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export default DisassembleARM;
|
|
@@ -9,13 +9,12 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
9
9
|
import { isImage } from "../lib/FileType.mjs";
|
|
10
10
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
11
11
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
|
12
|
-
import Jimp from "jimp
|
|
12
|
+
import { Jimp, JimpMime } from "jimp";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Image Dither operation
|
|
16
16
|
*/
|
|
17
17
|
class DitherImage extends Operation {
|
|
18
|
-
|
|
19
18
|
/**
|
|
20
19
|
* DitherImage constructor
|
|
21
20
|
*/
|
|
@@ -51,17 +50,19 @@ class DitherImage extends Operation {
|
|
|
51
50
|
try {
|
|
52
51
|
if (isWorkerEnvironment())
|
|
53
52
|
self.sendStatusMessage("Applying dither to image...");
|
|
54
|
-
image.
|
|
53
|
+
image.dither();
|
|
55
54
|
|
|
56
55
|
let imageBuffer;
|
|
57
|
-
if (image.
|
|
58
|
-
imageBuffer = await image.
|
|
56
|
+
if (image.mime === "image/gif") {
|
|
57
|
+
imageBuffer = await image.getBuffer(JimpMime.png);
|
|
59
58
|
} else {
|
|
60
|
-
imageBuffer = await image.
|
|
59
|
+
imageBuffer = await image.getBuffer(image.mime);
|
|
61
60
|
}
|
|
62
61
|
return imageBuffer.buffer;
|
|
63
62
|
} catch (err) {
|
|
64
|
-
throw new OperationError(
|
|
63
|
+
throw new OperationError(
|
|
64
|
+
`Error applying dither to image. (${err})`,
|
|
65
|
+
);
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -81,7 +82,6 @@ class DitherImage extends Operation {
|
|
|
81
82
|
|
|
82
83
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
83
84
|
}
|
|
84
|
-
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
export default DitherImage;
|