Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fuzzing improvements and bugfixes #466

Merged
merged 3 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -4907,7 +4907,8 @@ ZyanStatus ZydisDecoderInit(ZydisDecoder* decoder, ZydisMachineMode machine_mode
(1 << ZYDIS_DECODER_MODE_CET) |
(1 << ZYDIS_DECODER_MODE_LZCNT) |
(1 << ZYDIS_DECODER_MODE_TZCNT) |
(1 << ZYDIS_DECODER_MODE_CLDEMOTE);
(1 << ZYDIS_DECODER_MODE_CLDEMOTE) |
(1 << ZYDIS_DECODER_MODE_IPREFETCH);

if (!decoder)
{
Expand Down
4 changes: 4 additions & 0 deletions src/Encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -4527,6 +4527,10 @@ ZYDIS_EXPORT ZyanStatus ZydisEncoderEncodeInstructionAbsolute(ZydisEncoderReques
}
ZYAN_ASSERT(instruction.disp_size != 0);
ZyanU8 disp_offset = (instruction.disp_size >> 3) + (instruction.imm_size >> 3);
if (instruction.encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW)
{
disp_offset += 1;
}
ZYAN_ASSERT(instruction_size > disp_offset);
ZYAN_MEMCPY((ZyanU8 *)buffer + instruction_size - disp_offset, &rip_rel, sizeof(ZyanI32));
op_rip_rel->mem.displacement = rip_rel;
Expand Down
2 changes: 1 addition & 1 deletion tools/ZydisDisasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static void PrintDisassembly(const ZydisFormatter* formatter,
const ZydisFormatterToken* token;

if (!ZYAN_SUCCESS(status = ZydisFormatterTokenizeInstruction(formatter, instruction, operands,
instruction->operand_count_visible, buffer, length, runtime_address, &token, NULL)))
instruction->operand_count_visible, buffer, length, runtime_address, &token, ZYAN_NULL)))
{
PrintStatusError(status, "Failed to tokenize instruction");
exit(status);
Expand Down
8 changes: 4 additions & 4 deletions tools/ZydisFuzzDecoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,13 @@ int ZydisFuzzTarget(ZydisStreamRead read_fn, void* stream_ctx)
// Allow the control block to artificially restrict the buffer size.
ZyanUSize output_len = ZYAN_MIN(sizeof(format_buffer), control_block.formatter_max_len);
ZydisFormatterFormatInstruction(&formatter, &instruction, operands,
instruction.operand_count_visible, format_buffer, output_len, control_block.u64, NULL);
instruction.operand_count_visible, format_buffer, output_len, control_block.u64, ZYAN_NULL);

// Fuzz tokenizer.
const ZydisFormatterToken* token;
status = ZydisFormatterTokenizeInstruction(&formatter, &instruction, operands,
instruction.operand_count_visible, format_buffer, output_len, control_block.u64, &token,
NULL);
ZYAN_NULL);

// Walk tokens.
while (ZYAN_SUCCESS(status))
Expand All @@ -163,11 +163,11 @@ int ZydisFuzzTarget(ZydisStreamRead read_fn, void* stream_ctx)
const ZydisDecodedOperand* op = &operands[op_idx];

ZydisFormatterFormatOperand(&formatter, &instruction, op, format_buffer, output_len,
control_block.u64, NULL);
control_block.u64, ZYAN_NULL);

// Fuzz single operand tokenization.
ZydisFormatterTokenizeOperand(&formatter, &instruction, op, format_buffer, output_len,
control_block.u64, &token, NULL);
control_block.u64, &token, ZYAN_NULL);

// Address translation helper.
ZyanU64 abs_addr;
Expand Down
86 changes: 85 additions & 1 deletion tools/ZydisFuzzShared.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ void ZydisPrintInstruction(const ZydisDecodedInstruction* instruction,

char buffer[256];
ZydisFormatterFormatInstruction(&formatter, instruction, operands, operand_count, buffer,
sizeof(buffer), 0, NULL);
sizeof(buffer), 0, ZYAN_NULL);
printf(" %s\n", buffer);
}

Expand Down Expand Up @@ -370,6 +370,88 @@ void ZydisValidateInstructionIdentity(const ZydisDecodedInstruction* insn1,

#if !defined(ZYDIS_DISABLE_ENCODER)

static void ZydisReEncodeInstructionAbsolute(ZydisEncoderRequest* req,
const ZydisDecodedInstruction* insn2, const ZydisDecodedOperand* insn2_operands,
const ZyanU8* insn2_bytes)
{
ZyanU64 runtime_address;
switch (insn2->address_width)
{
case 16:
runtime_address = (ZyanU64)(ZyanU16)ZYAN_INT16_MIN;
break;
case 32:
runtime_address = (ZyanU64)(ZyanU32)ZYAN_INT32_MIN;
break;
case 64:
runtime_address = (ZyanU64)ZYAN_INT64_MIN;
break;
default:
ZYAN_UNREACHABLE;
}
if ((insn2->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) && (insn2->operand_width == 16))
{
runtime_address = (ZyanU64)(ZyanU16)ZYAN_INT16_MIN;
}
runtime_address -= insn2->length;

ZyanBool has_relative = ZYAN_FALSE;
for (ZyanU8 i = 0; i < req->operand_count; ++i)
{
const ZydisDecodedOperand *decoded_op = &insn2_operands[i];
ZydisEncoderOperand *op = &req->operands[i];
ZyanU64 *dst_address = ZYAN_NULL;
switch (op->type)
{
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
if (decoded_op->imm.is_relative)
{
dst_address = &op->imm.u;
}
break;
case ZYDIS_OPERAND_TYPE_MEMORY:
if ((decoded_op->mem.base == ZYDIS_REGISTER_EIP) ||
(decoded_op->mem.base == ZYDIS_REGISTER_RIP))
{
dst_address = (ZyanU64 *)&op->mem.displacement;
}
break;
default:
break;
}
if (!dst_address)
{
continue;
}
has_relative = ZYAN_TRUE;
if (!ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(insn2, decoded_op, runtime_address,
dst_address)))
{
fputs("ZydisCalcAbsoluteAddress has failed\n", ZYAN_STDERR);
abort();
}
}
if (!has_relative)
{
return;
}

ZyanU8 insn1_bytes[ZYDIS_MAX_INSTRUCTION_LENGTH];
ZyanUSize insn1_length = sizeof(insn1_bytes);
ZyanStatus status = ZydisEncoderEncodeInstructionAbsolute(req, insn1_bytes, &insn1_length,
runtime_address);
if (!ZYAN_SUCCESS(status))
{
fputs("Failed to re-encode instruction (absolute)\n", ZYAN_STDERR);
abort();
}
if (insn1_length != insn2->length || ZYAN_MEMCMP(insn1_bytes, insn2_bytes, insn2->length))
{
fputs("Instruction mismatch (absolute)\n", ZYAN_STDERR);
abort();
}
}

void ZydisReEncodeInstruction(const ZydisDecoder *decoder, const ZydisDecodedInstruction *insn1,
const ZydisDecodedOperand* operands1, ZyanU8 operand_count, const ZyanU8 *insn1_bytes)
{
Expand Down Expand Up @@ -415,6 +497,8 @@ void ZydisReEncodeInstruction(const ZydisDecoder *decoder, const ZydisDecodedIns
fputs("Suboptimal output size detected\n", ZYAN_STDERR);
abort();
}

ZydisReEncodeInstructionAbsolute(&request, &insn2, operands2, encoded_instruction);
}

#endif
Expand Down
4 changes: 2 additions & 2 deletions tools/ZydisInfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ static void PrintDisassembly(const ZydisDecodedInstruction* instruction,

PrintValueLabel("ABSOLUTE");
if (!ZYAN_SUCCESS(status = ZydisFormatterTokenizeInstruction(&formatter, instruction, operands,
instruction->operand_count_visible, buffer, sizeof(buffer), 0, &token, NULL)))
instruction->operand_count_visible, buffer, sizeof(buffer), 0, &token, ZYAN_NULL)))
{
PrintStatusError(status, "Failed to tokenize instruction");
exit(status);
Expand All @@ -847,7 +847,7 @@ static void PrintDisassembly(const ZydisDecodedInstruction* instruction,
PrintValueLabel("RELATIVE");
if (!ZYAN_SUCCESS(status = ZydisFormatterTokenizeInstruction(&formatter, instruction, operands,
instruction->operand_count_visible, buffer, sizeof(buffer), ZYDIS_RUNTIME_ADDRESS_NONE,
&token, NULL)))
&token, ZYAN_NULL)))
{
PrintStatusError(status, "Failed to tokenize instruction");
exit(status);
Expand Down
13 changes: 13 additions & 0 deletions tools/ZydisTestEncoderAbsolute.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,19 @@ static ZyanBool RunRipRelativeTests(void)
req.operands[1].reg.value = ZYDIS_REGISTER_EBX;
all_passed &= RunTest(&req, ZydisMnemonicGetString(req.mnemonic), 0, ZYAN_TRUE);

// AMD 3DNow!
ZYAN_MEMSET(&req, 0, sizeof(req));
req.machine_mode = ZYDIS_MACHINE_MODE_LONG_64;
req.mnemonic = ZYDIS_MNEMONIC_PI2FD;
req.operand_count = 2;
req.operands[0].type = ZYDIS_OPERAND_TYPE_REGISTER;
req.operands[0].reg.value = ZYDIS_REGISTER_MM1;
req.operands[1].type = ZYDIS_OPERAND_TYPE_MEMORY;
req.operands[1].mem.base = ZYDIS_REGISTER_RIP;
req.operands[1].mem.displacement = 0x66666666;
req.operands[1].mem.size = 8;
all_passed &= RunTest(&req, ZydisMnemonicGetString(req.mnemonic), 1, ZYAN_TRUE);

return all_passed;
}

Expand Down
Loading