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.
Files changed (101) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/CONTRIBUTING.md +37 -0
  3. package/Dockerfile +2 -0
  4. package/Gruntfile.js +0 -12
  5. package/README.md +1 -1
  6. package/babel.config.js +0 -6
  7. package/package.json +63 -62
  8. package/src/core/Chef.mjs +8 -1
  9. package/src/core/Ingredient.mjs +5 -2
  10. package/src/core/Operation.mjs +6 -1
  11. package/src/core/Recipe.mjs +10 -5
  12. package/src/core/config/Categories.json +18 -3
  13. package/src/core/config/OperationConfig.json +496 -23
  14. package/src/core/config/modules/Ciphers.mjs +6 -0
  15. package/src/core/config/modules/Crypto.mjs +6 -0
  16. package/src/core/config/modules/Default.mjs +6 -0
  17. package/src/core/config/modules/Shellcode.mjs +2 -0
  18. package/src/core/lib/AudioBytes.mjs +103 -0
  19. package/src/core/lib/AudioMetaSchema.mjs +82 -0
  20. package/src/core/lib/AudioParsers.mjs +630 -0
  21. package/src/core/lib/BigIntUtils.mjs +73 -0
  22. package/src/core/lib/Modhex.mjs +2 -0
  23. package/src/core/lib/QRCode.mjs +30 -10
  24. package/src/core/lib/RC6.mjs +625 -0
  25. package/src/core/operations/A1Z26CipherDecode.mjs +1 -1
  26. package/src/core/operations/AddTextToImage.mjs +116 -64
  27. package/src/core/operations/BlurImage.mjs +10 -12
  28. package/src/core/operations/ContainImage.mjs +50 -40
  29. package/src/core/operations/ConvertImageFormat.mjs +33 -39
  30. package/src/core/operations/CoverImage.mjs +39 -37
  31. package/src/core/operations/CropImage.mjs +35 -21
  32. package/src/core/operations/DisassembleARM.mjs +193 -0
  33. package/src/core/operations/DitherImage.mjs +8 -8
  34. package/src/core/operations/EscapeUnicodeCharacters.mjs +0 -17
  35. package/src/core/operations/ExtractAudioMetadata.mjs +175 -0
  36. package/src/core/operations/ExtractLSB.mjs +17 -11
  37. package/src/core/operations/ExtractRGBA.mjs +12 -10
  38. package/src/core/operations/FlaskSessionDecode.mjs +80 -0
  39. package/src/core/operations/FlaskSessionSign.mjs +89 -0
  40. package/src/core/operations/FlaskSessionVerify.mjs +136 -0
  41. package/src/core/operations/FlipImage.mjs +14 -10
  42. package/src/core/operations/GenerateImage.mjs +39 -32
  43. package/src/core/operations/ImageBrightnessContrast.mjs +10 -10
  44. package/src/core/operations/ImageFilter.mjs +14 -13
  45. package/src/core/operations/ImageHueSaturationLightness.mjs +22 -20
  46. package/src/core/operations/ImageOpacity.mjs +6 -8
  47. package/src/core/operations/InvertImage.mjs +4 -6
  48. package/src/core/operations/Jq.mjs +12 -4
  49. package/src/core/operations/NormaliseImage.mjs +5 -7
  50. package/src/core/operations/OffsetChecker.mjs +1 -1
  51. package/src/core/operations/ParseEthernetFrame.mjs +112 -0
  52. package/src/core/operations/ParseIPv4Header.mjs +23 -6
  53. package/src/core/operations/ParseQRCode.mjs +13 -13
  54. package/src/core/operations/PseudoRandomIntegerGenerator.mjs +164 -0
  55. package/src/core/operations/RC6Decrypt.mjs +119 -0
  56. package/src/core/operations/RC6Encrypt.mjs +119 -0
  57. package/src/core/operations/RandomizeColourPalette.mjs +11 -11
  58. package/src/core/operations/ResizeImage.mjs +30 -23
  59. package/src/core/operations/RotateImage.mjs +8 -9
  60. package/src/core/operations/SQLBeautify.mjs +21 -3
  61. package/src/core/operations/SharpenImage.mjs +94 -62
  62. package/src/core/operations/SplitColourChannels.mjs +47 -21
  63. package/src/core/operations/TextIntegerConverter.mjs +123 -0
  64. package/src/core/operations/UnescapeUnicodeCharacters.mjs +17 -0
  65. package/src/core/operations/ViewBitPlane.mjs +16 -20
  66. package/src/core/operations/index.mjs +20 -0
  67. package/src/node/index.mjs +50 -0
  68. package/src/web/HTMLIngredient.mjs +24 -43
  69. package/src/web/Manager.mjs +1 -0
  70. package/src/web/html/index.html +6 -6
  71. package/src/web/static/fonts/bmfonts/Roboto72White.fnt +491 -485
  72. package/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt +494 -488
  73. package/src/web/static/fonts/bmfonts/RobotoMono72White.fnt +110 -103
  74. package/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt +498 -492
  75. package/src/web/stylesheets/layout/_banner.css +30 -0
  76. package/src/web/stylesheets/layout/_modals.css +5 -0
  77. package/src/web/stylesheets/utils/_overrides.css +7 -0
  78. package/src/web/waiters/ControlsWaiter.mjs +82 -0
  79. package/src/web/waiters/InputWaiter.mjs +12 -6
  80. package/src/web/waiters/RecipeWaiter.mjs +2 -2
  81. package/tests/browser/02_ops.js +23 -3
  82. package/tests/node/index.mjs +1 -0
  83. package/tests/node/tests/lib/BigIntUtils.mjs +150 -0
  84. package/tests/node/tests/operations.mjs +9 -7
  85. package/tests/operations/index.mjs +8 -0
  86. package/tests/operations/tests/A1Z26CipherDecode.mjs +33 -0
  87. package/tests/operations/tests/DisassembleARM.mjs +377 -0
  88. package/tests/operations/tests/ExtractAudioMetadata.mjs +287 -0
  89. package/tests/operations/tests/FlaskSession.mjs +246 -0
  90. package/tests/operations/tests/GenerateQRCode.mjs +67 -0
  91. package/tests/operations/tests/JWTSign.mjs +83 -8
  92. package/tests/operations/tests/Jq.mjs +32 -0
  93. package/tests/operations/tests/Modhex.mjs +20 -0
  94. package/tests/operations/tests/ParseEthernetFrame.mjs +45 -0
  95. package/tests/operations/tests/RC6.mjs +487 -0
  96. package/tests/operations/tests/SQLBeautify.mjs +54 -0
  97. package/tests/operations/tests/TextIntegerConverter.mjs +199 -0
  98. package/tests/samples/Audio.mjs +73 -0
  99. package/tests/samples/Images.mjs +0 -12
  100. package/webpack.config.js +10 -7
  101. 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/es/index.js";
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 = "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.";
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
- "JPEG": Jimp.MIME_JPEG,
80
- "PNG": Jimp.MIME_PNG,
81
- "BMP": Jimp.MIME_BMP,
82
- "TIFF": Jimp.MIME_TIFF
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
- "Auto": Jimp.PNG_FILTER_AUTO,
87
- "None": Jimp.PNG_FILTER_NONE,
88
- "Sub": Jimp.PNG_FILTER_SUB,
89
- "Up": Jimp.PNG_FILTER_UP,
90
- "Average": Jimp.PNG_FILTER_AVERAGE,
91
- "Paeth": Jimp.PNG_FILTER_PATH
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
- switch (format) {
107
- case "JPEG":
108
- image.quality(jpegQuality);
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 "PNG":
111
- image.filterType(pngFilterMap[pngFilterType]);
112
- image.deflateLevel(pngDeflateLevel);
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
- const imageBuffer = await image.getBufferAsync(mime);
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 jimp from "jimp/es/index.js";
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 = "Scales the image to the given width and height, keeping the aspect ratio. The image may be clipped.";
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
- "Left",
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
- "Top",
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": jimp.RESIZE_NEAREST_NEIGHBOR,
90
- "Bilinear": jimp.RESIZE_BILINEAR,
91
- "Bicubic": jimp.RESIZE_BICUBIC,
92
- "Hermite": jimp.RESIZE_HERMITE,
93
- "Bezier": jimp.RESIZE_BEZIER
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
- "Left": jimp.HORIZONTAL_ALIGN_LEFT,
98
- "Center": jimp.HORIZONTAL_ALIGN_CENTER,
99
- "Right": jimp.HORIZONTAL_ALIGN_RIGHT,
100
- "Top": jimp.VERTICAL_ALIGN_TOP,
101
- "Middle": jimp.VERTICAL_ALIGN_MIDDLE,
102
- "Bottom": jimp.VERTICAL_ALIGN_BOTTOM
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 jimp.read(input);
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(width, height, alignMap[hAlign] | alignMap[vAlign], resizeMap[alg]);
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.getMIME() === "image/gif") {
121
- imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
123
+ if (image.mime === "image/gif") {
124
+ imageBuffer = await image.getBuffer(JimpMime.png);
122
125
  } else {
123
- imageBuffer = await image.getBufferAsync(jimp.AUTO);
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/es/index.js";
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 = "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.";
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 [xPos, yPos, width, height, autocrop, autoTolerance, autoFrames, autoSymmetric, autoBorder] = args;
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: (autoTolerance / 100),
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(xPos, yPos, width, height);
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.getMIME() === "image/gif") {
122
- imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
136
+ if (image.mime === "image/gif") {
137
+ imageBuffer = await image.getBuffer(JimpMime.png);
123
138
  } else {
124
- imageBuffer = await image.getBufferAsync(Jimp.AUTO);
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/es/index.js";
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.dither565();
53
+ image.dither();
55
54
 
56
55
  let imageBuffer;
57
- if (image.getMIME() === "image/gif") {
58
- imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
56
+ if (image.mime === "image/gif") {
57
+ imageBuffer = await image.getBuffer(JimpMime.png);
59
58
  } else {
60
- imageBuffer = await image.getBufferAsync(Jimp.AUTO);
59
+ imageBuffer = await image.getBuffer(image.mime);
61
60
  }
62
61
  return imageBuffer.buffer;
63
62
  } catch (err) {
64
- throw new OperationError(`Error applying dither to image. (${err})`);
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;