fix: accept hexadecimal values for Disassemble x86 address arguments
The 'Code Segment (CS)' and 'Offset (IP)' arguments were declared as
'number' ingredients, so they were parsed with parseFloat and rejected
hexadecimal input such as '0xABC' with:
Invalid ingredient value. Not a number: NaN
However, SetBasePosition already parses both values with parseInt(x, 16)
and GetPosition renders them back out with toString(16), so these fields
have always been hexadecimal. The two conversions cancel out visually,
which is why the mismatch went unnoticed. It is observable though: a code
segment entered as '24' becomes 36 decimal internally, which crosses the
documented 'CS >= 36 switches 32-bit output to SEG:OFFSET' threshold.
Both arguments are now 'string' ingredients parsed by a dedicated helper
that accepts bare ('ABC'), prefixed ('0xABC') and suffixed ('ABCh') hex,
and rejects anything else with a named error instead of a NaN message.
The code segment is left-padded to four digits because SetBasePosition
reads it via slice(length - 4), which silently truncated shorter values
('ABC' was read as 'C').
Existing recipes are unaffected: the default is unchanged and numeric
argument values from saved recipes are still handled.
Fixes #2720
This commit is contained in:
parent
4290ea7539
commit
3a2fb20479
@ -8,6 +8,34 @@ import Operation from "../Operation.mjs";
|
||||
import * as disassemble from "../vendor/DisassembleX86-64.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Parses a hexadecimal address value used by the disassembler.
|
||||
*
|
||||
* The underlying disassembler interprets both the code segment and the offset as
|
||||
* hexadecimal, and renders them back as hexadecimal, so these arguments accept the
|
||||
* common ways of writing a hex literal: bare (`ABC`), prefixed (`0xABC`) or suffixed
|
||||
* (`ABCh`).
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {string} name - Argument name, used in the error message.
|
||||
* @param {number} [padTo=0] - Left-pad the result with zeroes to this many digits.
|
||||
* @returns {string} The bare hex digits, ready to be passed to SetBasePosition.
|
||||
*
|
||||
* @throws {OperationError} if the value is not a valid hexadecimal number.
|
||||
*/
|
||||
function parseHexAddress(value, name, padTo = 0) {
|
||||
const trimmed = value.toString().trim();
|
||||
const hex = trimmed.replace(/^0x/i, "").replace(/h$/i, "");
|
||||
|
||||
if (hex === "" || !/^[\da-f]+$/i.test(hex)) {
|
||||
throw new OperationError(`Invalid ${name}: '${trimmed}' is not a hexadecimal number.`);
|
||||
}
|
||||
|
||||
// SetBasePosition reads the code segment from the last four characters it is given,
|
||||
// so shorter values must be padded to avoid losing their leading digits.
|
||||
return hex.padStart(padTo, "0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassemble x86 operation
|
||||
*/
|
||||
@ -46,13 +74,15 @@ class DisassembleX86 extends Operation {
|
||||
},
|
||||
{
|
||||
"name": "Code Segment (CS)",
|
||||
"type": "number",
|
||||
"value": 16
|
||||
"type": "string",
|
||||
"value": "16",
|
||||
"hint": "Hexadecimal, e.g. 16, 0xABC or ABCh"
|
||||
},
|
||||
{
|
||||
"name": "Offset (IP)",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
"type": "string",
|
||||
"value": "0",
|
||||
"hint": "Hexadecimal, e.g. 0, 0x1000 or 1000h"
|
||||
},
|
||||
{
|
||||
"name": "Show instruction hex",
|
||||
@ -122,7 +152,10 @@ class DisassembleX86 extends Operation {
|
||||
break;
|
||||
}
|
||||
|
||||
disassemble.SetBasePosition(codeSegment + ":" + offset);
|
||||
disassemble.SetBasePosition(
|
||||
parseHexAddress(codeSegment, "Code Segment (CS)", 4) + ":" +
|
||||
parseHexAddress(offset, "Offset (IP)")
|
||||
);
|
||||
disassemble.setShowInstructionHex(showInstructionHex);
|
||||
disassemble.setShowInstructionPos(showInstructionPos);
|
||||
disassemble.LoadBinCode(input.replace(/\s/g, ""));
|
||||
|
||||
89
tests/operations/tests/DisassembleX86.mjs
Normal file
89
tests/operations/tests/DisassembleX86.mjs
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Disassemble x86 tests.
|
||||
*
|
||||
* @author arjun2075
|
||||
*
|
||||
* @copyright Crown Copyright 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Disassemble x86: default code segment is unchanged",
|
||||
input: "90",
|
||||
expectedMatch: /0016:0000\s+NOP/,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Disassemble x86",
|
||||
args: ["16", "Full x86 architecture", "16", "0", false, true],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Disassemble x86: hex code segment with 0x prefix",
|
||||
input: "90",
|
||||
expectedMatch: /0ABC:0000\s+NOP/,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Disassemble x86",
|
||||
args: ["16", "Full x86 architecture", "0xABC", "0", false, true],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Disassemble x86: hex code segment with h suffix",
|
||||
input: "90",
|
||||
expectedMatch: /0ABC:0000\s+NOP/,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Disassemble x86",
|
||||
args: ["16", "Full x86 architecture", "ABCh", "0", false, true],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Disassemble x86: bare hex code segment",
|
||||
input: "90",
|
||||
expectedMatch: /0ABC:0000\s+NOP/,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Disassemble x86",
|
||||
args: ["16", "Full x86 architecture", "ABC", "0", false, true],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Disassemble x86: hex offset with 0x prefix",
|
||||
input: "90",
|
||||
expectedMatch: /0016:1000\s+NOP/,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Disassemble x86",
|
||||
args: ["16", "Full x86 architecture", "16", "0x1000", false, true],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Disassemble x86: invalid code segment is rejected",
|
||||
input: "90",
|
||||
expectedOutput: "Invalid Code Segment (CS): 'wibble' is not a hexadecimal number.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Disassemble x86",
|
||||
args: ["16", "Full x86 architecture", "wibble", "0", false, true],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Disassemble x86: invalid offset is rejected",
|
||||
input: "90",
|
||||
expectedOutput: "Invalid Offset (IP): 'wibble' is not a hexadecimal number.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Disassemble x86",
|
||||
args: ["16", "Full x86 architecture", "16", "wibble", false, true],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
Loading…
x
Reference in New Issue
Block a user