mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-05 05:58:19 +01:00
Squashed 'externals/zydis/' content from commit 25193db00
git-subtree-dir: externals/zydis git-subtree-split: 25193db008e8799ff59fd655c2a26b2ffd79d40d
This commit is contained in:
commit
6ee9beab32
452 changed files with 78725 additions and 0 deletions
163
examples/Formatter01.c
Normal file
163
examples/Formatter01.c
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Demonstrates basic hooking functionality of the `ZydisFormatter` class by implementing
|
||||
* a custom symbol-resolver.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <Zycore/Format.h>
|
||||
#include <Zycore/LibC.h>
|
||||
#include <Zydis/Zydis.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and Types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisSymbol` struct.
|
||||
*/
|
||||
typedef struct ZydisSymbol_
|
||||
{
|
||||
/**
|
||||
* The symbol address.
|
||||
*/
|
||||
ZyanU64 address;
|
||||
/**
|
||||
* The symbol name.
|
||||
*/
|
||||
const char* name;
|
||||
} ZydisSymbol;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Static data */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* A static symbol table with some dummy symbols.
|
||||
*/
|
||||
static const ZydisSymbol SYMBOL_TABLE[3] =
|
||||
{
|
||||
{ 0x007FFFFFFF401000, "SomeModule.EntryPoint" },
|
||||
{ 0x007FFFFFFF530040, "SomeModule.SomeData" },
|
||||
{ 0x007FFFFFFF401100, "SomeModule.SomeFunction" }
|
||||
};
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Hook callbacks */
|
||||
/* ============================================================================================== */
|
||||
|
||||
ZydisFormatterFunc default_print_address_absolute;
|
||||
|
||||
static ZyanStatus ZydisFormatterPrintAddressAbsolute(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
||||
{
|
||||
ZyanU64 address;
|
||||
ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand,
|
||||
context->runtime_address, &address));
|
||||
|
||||
for (ZyanUSize i = 0; i < ZYAN_ARRAY_LENGTH(SYMBOL_TABLE); ++i)
|
||||
{
|
||||
if (SYMBOL_TABLE[i].address == address)
|
||||
{
|
||||
ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, ZYDIS_TOKEN_SYMBOL));
|
||||
ZyanString* string;
|
||||
ZYAN_CHECK(ZydisFormatterBufferGetString(buffer, &string));
|
||||
return ZyanStringAppendFormat(string, "<%s>", SYMBOL_TABLE[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
return default_print_address_absolute(formatter, buffer, context);
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Helper functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
static void DisassembleBuffer(ZydisDecoder* decoder, ZyanU8* data, ZyanUSize length)
|
||||
{
|
||||
ZydisFormatter formatter;
|
||||
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
|
||||
ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_FORCE_SEGMENT, ZYAN_TRUE);
|
||||
ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE);
|
||||
|
||||
// Replace the `ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS` function that formats the absolute
|
||||
// addresses
|
||||
default_print_address_absolute = (ZydisFormatterFunc)&ZydisFormatterPrintAddressAbsolute;
|
||||
ZydisFormatterSetHook(&formatter, ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS,
|
||||
(const void**)&default_print_address_absolute);
|
||||
|
||||
ZyanU64 runtime_address = 0x007FFFFFFF400000;
|
||||
|
||||
ZydisDecodedInstruction instruction;
|
||||
char buffer[256];
|
||||
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(decoder, data, length, &instruction)))
|
||||
{
|
||||
ZYAN_PRINTF("%016" PRIX64 " ", runtime_address);
|
||||
// We have to pass a `runtime_address` different to `ZYDIS_RUNTIME_ADDRESS_NONE` to
|
||||
// enable printing of absolute addresses
|
||||
ZydisFormatterFormatInstruction(&formatter, &instruction, &buffer[0], sizeof(buffer),
|
||||
runtime_address);
|
||||
ZYAN_PRINTF(" %s\n", &buffer[0]);
|
||||
data += instruction.length;
|
||||
length -= instruction.length;
|
||||
runtime_address += instruction.length;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Entry point */
|
||||
/* ============================================================================================== */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (ZydisGetVersion() != ZYDIS_VERSION)
|
||||
{
|
||||
fputs("Invalid zydis version\n", ZYAN_STDERR);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ZyanU8 data[] =
|
||||
{
|
||||
0x48, 0x8B, 0x05, 0x39, 0x00, 0x13, 0x00, // mov rax, qword ptr ds:[<SomeModule.SomeData>]
|
||||
0x50, // push rax
|
||||
0xFF, 0x15, 0xF2, 0x10, 0x00, 0x00, // call qword ptr ds:[<SomeModule.SomeFunction>]
|
||||
0x85, 0xC0, // test eax, eax
|
||||
0x0F, 0x84, 0x00, 0x00, 0x00, 0x00, // jz 0x007FFFFFFF400016
|
||||
0xE9, 0xE5, 0x0F, 0x00, 0x00 // jmp <SomeModule.EntryPoint>
|
||||
};
|
||||
|
||||
ZydisDecoder decoder;
|
||||
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
|
||||
|
||||
DisassembleBuffer(&decoder, &data[0], sizeof(data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
265
examples/Formatter02.c
Normal file
265
examples/Formatter02.c
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Demonstrates basic hooking functionality of the `ZydisFormatter` class and the ability
|
||||
* to completely omit specific operands.
|
||||
*
|
||||
* This example demonstrates the hooking functionality of the `ZydisFormatter` class by
|
||||
* rewriting the mnemonics of `(V)CMPPS` and `(V)CMPPD` to their corresponding alias-forms (based
|
||||
* on the condition encoded in the immediate operand).
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <Zycore/Format.h>
|
||||
#include <Zycore/LibC.h>
|
||||
#include <Zydis/Zydis.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Static data */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Static array with the condition-code strings.
|
||||
*/
|
||||
static const char* const CONDITION_CODE_STRINGS[0x20] =
|
||||
{
|
||||
/*00*/ "eq",
|
||||
/*01*/ "lt",
|
||||
/*02*/ "le",
|
||||
/*03*/ "unord",
|
||||
/*04*/ "neq",
|
||||
/*05*/ "nlt",
|
||||
/*06*/ "nle",
|
||||
/*07*/ "ord",
|
||||
/*08*/ "eq_uq",
|
||||
/*09*/ "nge",
|
||||
/*0A*/ "ngt",
|
||||
/*0B*/ "false",
|
||||
/*0C*/ "oq",
|
||||
/*0D*/ "ge",
|
||||
/*0E*/ "gt",
|
||||
/*0F*/ "true",
|
||||
/*10*/ "eq_os",
|
||||
/*11*/ "lt_oq",
|
||||
/*12*/ "le_oq",
|
||||
/*13*/ "unord_s",
|
||||
/*14*/ "neq_us",
|
||||
/*15*/ "nlt_uq",
|
||||
/*16*/ "nle_uq",
|
||||
/*17*/ "ord_s",
|
||||
/*18*/ "eq_us",
|
||||
/*19*/ "nge_uq",
|
||||
/*1A*/ "ngt_uq",
|
||||
/*1B*/ "false_os",
|
||||
/*1C*/ "neq_os",
|
||||
/*1D*/ "ge_oq",
|
||||
/*1E*/ "gt_oq",
|
||||
/*1F*/ "true_us"
|
||||
};
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and Types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Custom user data struct for the formatter.
|
||||
*/
|
||||
typedef struct ZydisCustomUserData_
|
||||
{
|
||||
ZyanBool omit_immediate;
|
||||
} ZydisCustomUserData;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Hook callbacks */
|
||||
/* ============================================================================================== */
|
||||
|
||||
ZydisFormatterFunc default_print_mnemonic;
|
||||
|
||||
static ZyanStatus ZydisFormatterPrintMnemonic(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
||||
{
|
||||
// We use the user-data to pass data to the `ZydisFormatterFormatOperandImm` function
|
||||
ZydisCustomUserData* user_data = (ZydisCustomUserData*)context->user_data;
|
||||
user_data->omit_immediate = ZYAN_TRUE;
|
||||
|
||||
// Rewrite the instruction-mnemonic for the given instructions
|
||||
if (context->instruction->operand_count &&
|
||||
context->instruction->operands[context->instruction->operand_count - 1].type ==
|
||||
ZYDIS_OPERAND_TYPE_IMMEDIATE)
|
||||
{
|
||||
// Retrieve the `ZyanString` instance of the formatter-buffer
|
||||
ZyanString* string;
|
||||
ZYAN_CHECK(ZydisFormatterBufferGetString(buffer, &string));
|
||||
|
||||
const ZyanU8 condition_code = (ZyanU8)context->instruction->operands[
|
||||
context->instruction->operand_count - 1].imm.value.u;
|
||||
switch (context->instruction->mnemonic)
|
||||
{
|
||||
case ZYDIS_MNEMONIC_CMPPS:
|
||||
if (condition_code < 0x08)
|
||||
{
|
||||
ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, ZYDIS_TOKEN_MNEMONIC));
|
||||
return ZyanStringAppendFormat(string, "cmp%sps",
|
||||
CONDITION_CODE_STRINGS[condition_code]);
|
||||
}
|
||||
break;
|
||||
case ZYDIS_MNEMONIC_CMPPD:
|
||||
if (condition_code < 0x08)
|
||||
{
|
||||
ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, ZYDIS_TOKEN_MNEMONIC));
|
||||
return ZyanStringAppendFormat(string, "cmp%spd",
|
||||
CONDITION_CODE_STRINGS[condition_code]);
|
||||
}
|
||||
break;
|
||||
case ZYDIS_MNEMONIC_VCMPPS:
|
||||
if (condition_code < 0x20)
|
||||
{
|
||||
ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, ZYDIS_TOKEN_MNEMONIC));
|
||||
return ZyanStringAppendFormat(string, "vcmp%sps",
|
||||
CONDITION_CODE_STRINGS[condition_code]);
|
||||
}
|
||||
break;
|
||||
case ZYDIS_MNEMONIC_VCMPPD:
|
||||
if (condition_code < 0x20)
|
||||
{
|
||||
ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, ZYDIS_TOKEN_MNEMONIC));
|
||||
return ZyanStringAppendFormat(string, "vcmp%spd",
|
||||
CONDITION_CODE_STRINGS[condition_code]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We did not rewrite the instruction-mnemonic. Signal the `ZydisFormatterFormatOperandImm`
|
||||
// function not to omit the operand
|
||||
user_data->omit_immediate = ZYAN_FALSE;
|
||||
|
||||
// Default mnemonic printing
|
||||
return default_print_mnemonic(formatter, buffer, context);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZydisFormatterFunc default_format_operand_imm;
|
||||
|
||||
static ZyanStatus ZydisFormatterFormatOperandIMM(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
||||
{
|
||||
// The `ZydisFormatterFormatMnemonic` sinals us to omit the immediate (condition-code)
|
||||
// operand, because it got replaced by the alias-mnemonic
|
||||
const ZydisCustomUserData* user_data = (ZydisCustomUserData*)context->user_data;
|
||||
if (user_data->omit_immediate)
|
||||
{
|
||||
return ZYDIS_STATUS_SKIP_TOKEN;
|
||||
}
|
||||
|
||||
// Default immediate formatting
|
||||
return default_format_operand_imm(formatter, buffer, context);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Helper functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
static void DisassembleBuffer(ZydisDecoder* decoder, ZyanU8* data, ZyanUSize length,
|
||||
ZyanBool install_hooks)
|
||||
{
|
||||
ZydisFormatter formatter;
|
||||
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
|
||||
ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_FORCE_SEGMENT, ZYAN_TRUE);
|
||||
ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE);
|
||||
|
||||
if (install_hooks)
|
||||
{
|
||||
default_print_mnemonic = (ZydisFormatterFunc)&ZydisFormatterPrintMnemonic;
|
||||
ZydisFormatterSetHook(&formatter, ZYDIS_FORMATTER_FUNC_PRINT_MNEMONIC,
|
||||
(const void**)&default_print_mnemonic);
|
||||
default_format_operand_imm = (ZydisFormatterFunc)&ZydisFormatterFormatOperandIMM;
|
||||
ZydisFormatterSetHook(&formatter, ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM,
|
||||
(const void**)&default_format_operand_imm);
|
||||
}
|
||||
|
||||
ZyanU64 runtime_address = 0x007FFFFFFF400000;
|
||||
|
||||
ZydisDecodedInstruction instruction;
|
||||
ZydisCustomUserData user_data;
|
||||
char buffer[256];
|
||||
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(decoder, data, length, &instruction)))
|
||||
{
|
||||
ZYAN_PRINTF("%016" PRIX64 " ", runtime_address);
|
||||
ZydisFormatterFormatInstructionEx(&formatter, &instruction, &buffer[0], sizeof(buffer),
|
||||
runtime_address, &user_data);
|
||||
ZYAN_PRINTF(" %s\n", &buffer[0]);
|
||||
data += instruction.length;
|
||||
length -= instruction.length;
|
||||
runtime_address += instruction.length;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Entry point */
|
||||
/* ============================================================================================== */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (ZydisGetVersion() != ZYDIS_VERSION)
|
||||
{
|
||||
fputs("Invalid zydis version\n", ZYAN_STDERR);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ZyanU8 data[] =
|
||||
{
|
||||
// nop
|
||||
0x90,
|
||||
|
||||
// cmpps xmm1, xmm4, 0x03
|
||||
0x0F, 0xC2, 0xCC, 0x03,
|
||||
|
||||
// vcmppd xmm1, xmm2, xmm3, 0x17
|
||||
0xC5, 0xE9, 0xC2, 0xCB, 0x17,
|
||||
|
||||
// vcmpps k2 {k7}, zmm2, dword ptr ds:[rax + rbx*4 + 0x100] {1to16}, 0x0F
|
||||
0x62, 0xF1, 0x6C, 0x5F, 0xC2, 0x54, 0x98, 0x40, 0x0F
|
||||
};
|
||||
|
||||
ZydisDecoder decoder;
|
||||
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
|
||||
|
||||
DisassembleBuffer(&decoder, &data[0], sizeof(data), ZYAN_FALSE);
|
||||
ZYAN_PUTS("");
|
||||
DisassembleBuffer(&decoder, &data[0], sizeof(data), ZYAN_TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
126
examples/Formatter03.c
Normal file
126
examples/Formatter03.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Demonstrates the tokenizing feature of the `ZydisFormatter` class.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <Zycore/Format.h>
|
||||
#include <Zycore/LibC.h>
|
||||
#include <Zydis/Zydis.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Static data */
|
||||
/* ============================================================================================== */
|
||||
|
||||
static const char* const TOKEN_TYPES[] =
|
||||
{
|
||||
"INVALID ",
|
||||
"WHITESPACE ",
|
||||
"DELIMITER ",
|
||||
"PARENTHESIS_OPEN ",
|
||||
"PARENTHESIS_CLOSE",
|
||||
"PREFIX ",
|
||||
"MNEMONIC ",
|
||||
"REGISTER ",
|
||||
"ADDRESS_ABS ",
|
||||
"ADDRESS_REL ",
|
||||
"DISPLACEMENT ",
|
||||
"IMMEDIATE ",
|
||||
"TYPECAST ",
|
||||
"DECORATOR ",
|
||||
"SYMBOL "
|
||||
};
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Helper functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
static void DisassembleBuffer(ZydisDecoder* decoder, ZyanU8* data, ZyanUSize length)
|
||||
{
|
||||
ZydisFormatter formatter;
|
||||
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
|
||||
ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_FORCE_SEGMENT, ZYAN_TRUE);
|
||||
ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE);
|
||||
|
||||
ZyanU64 runtime_address = 0x007FFFFFFF400000;
|
||||
|
||||
ZydisDecodedInstruction instruction;
|
||||
char buffer[256];
|
||||
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(decoder, data, length, &instruction)))
|
||||
{
|
||||
const ZydisFormatterToken* token;
|
||||
if (ZYAN_SUCCESS(ZydisFormatterTokenizeInstruction(&formatter, &instruction, &buffer[0],
|
||||
sizeof(buffer), runtime_address, &token)))
|
||||
{
|
||||
ZydisTokenType token_type;
|
||||
ZyanConstCharPointer token_value = ZYAN_NULL;
|
||||
while (token)
|
||||
{
|
||||
ZydisFormatterTokenGetValue(token, &token_type, &token_value);
|
||||
printf("ZYDIS_TOKEN_%17s (%02X): \"%s\"\n", TOKEN_TYPES[token_type], token_type,
|
||||
token_value);
|
||||
if (!ZYAN_SUCCESS(ZydisFormatterTokenNext(&token)))
|
||||
{
|
||||
token = ZYAN_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
data += instruction.length;
|
||||
length -= instruction.length;
|
||||
runtime_address += instruction.length;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Entry point */
|
||||
/* ============================================================================================== */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (ZydisGetVersion() != ZYDIS_VERSION)
|
||||
{
|
||||
fputs("Invalid zydis version\n", ZYAN_STDERR);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ZyanU8 data[] =
|
||||
{
|
||||
// vcmpps k2 {k7}, zmm2, dword ptr ds:[rax + rbx*4 + 0x100] {1to16}, 0x0F
|
||||
0x62, 0xF1, 0x6C, 0x5F, 0xC2, 0x54, 0x98, 0x40, 0x0F
|
||||
};
|
||||
|
||||
ZydisDecoder decoder;
|
||||
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
|
||||
|
||||
DisassembleBuffer(&decoder, &data[0], sizeof(data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
23
examples/README.md
Normal file
23
examples/README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Zydis Examples
|
||||
|
||||
## Decoder
|
||||
|
||||
Comming soon™ ...
|
||||
|
||||
## Formatter
|
||||
|
||||
### [Formatter01](./Formatter01.c)
|
||||
Demonstrates basic hooking functionality of the `ZydisFormatter` class by implementing a custom symbol-resolver.
|
||||
|
||||
### [Formatter02](./Formatter02.c)
|
||||
Demonstrates basic hooking functionality of the `ZydisFormatter` class and the ability to completely omit specific operands.
|
||||
|
||||
The example demonstrates the hooking functionality of the `ZydisFormatter` class by rewriting the mnemonics of `(V)CMPPS` and `(V)CMPPD` to their corresponding alias-forms (based on the condition encoded in the immediate operand).
|
||||
|
||||
### [Formatter03](./Formatter03.c)
|
||||
Demonstrates the tokenizing feature of the `ZydisFormatter` class.
|
||||
|
||||
## Misc
|
||||
|
||||
### [ZydisWinKernel](./ZydisWinKernel.c)
|
||||
Implements an example Windows kernel-mode driver.
|
||||
578
examples/ZydisPerfTest.c
Normal file
578
examples/ZydisPerfTest.c
Normal file
|
|
@ -0,0 +1,578 @@
|
|||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <Zycore/API/Terminal.h>
|
||||
#include <Zycore/LibC.h>
|
||||
#include <Zydis/Zydis.h>
|
||||
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
# include <Windows.h>
|
||||
#elif defined(ZYAN_APPLE)
|
||||
# include <mach/mach_time.h>
|
||||
#elif defined(ZYAN_LINUX) || defined(ZYAN_SOLARIS)
|
||||
# include <sys/time.h>
|
||||
# include <pthread.h>
|
||||
#elif defined(ZYAN_FREEBSD)
|
||||
# include <sys/time.h>
|
||||
# include <pthread.h>
|
||||
# include <pthread_np.h>
|
||||
#else
|
||||
# error "Unsupported platform detected"
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Colors */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Configuration */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define COLOR_DEFAULT ZYAN_VT100SGR_FG_DEFAULT
|
||||
#define COLOR_ERROR ZYAN_VT100SGR_FG_BRIGHT_RED
|
||||
#define COLOR_VALUE_R ZYAN_VT100SGR_FG_BRIGHT_RED
|
||||
#define COLOR_VALUE_G ZYAN_VT100SGR_FG_BRIGHT_GREEN
|
||||
#define COLOR_VALUE_B ZYAN_VT100SGR_FG_CYAN
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Global variables */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
static ZyanBool g_vt100_stdout;
|
||||
static ZyanBool g_vt100_stderr;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Helper macros */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Conditionally expands to the passed VT100 sequence, if `g_colors_stdout` is
|
||||
* `ZYAN_TRUE`, or an empty string, if not.
|
||||
*
|
||||
* @param The VT100 SGT sequence.
|
||||
*/
|
||||
#define CVT100_OUT(sequence) (g_vt100_stdout ? (sequence) : "")
|
||||
|
||||
/**
|
||||
* Conditionally expands to the passed VT100 sequence, if `g_colors_stderr` is
|
||||
* `ZYAN_TRUE`, or an empty string, if not.
|
||||
*
|
||||
* @param The VT100 SGT sequence.
|
||||
*/
|
||||
#define CVT100_ERR(sequence) (g_vt100_stderr ? (sequence) : "")
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Helper functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Time measurement */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
|
||||
double counter_freq = 0.0;
|
||||
ZyanU64 counter_start = 0;
|
||||
|
||||
static void StartCounter(void)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
if (!QueryPerformanceFrequency(&li))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sError: QueryPerformanceFrequency failed!%s\n",
|
||||
CVT100_ERR(COLOR_ERROR), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
counter_freq = (double)li.QuadPart / 1000.0;
|
||||
QueryPerformanceCounter(&li);
|
||||
counter_start = li.QuadPart;
|
||||
}
|
||||
|
||||
static double GetCounter(void)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceCounter(&li);
|
||||
return (double)(li.QuadPart - counter_start) / counter_freq;
|
||||
}
|
||||
|
||||
#elif defined(ZYAN_APPLE)
|
||||
|
||||
ZyanU64 counter_start = 0;
|
||||
mach_timebase_info_data_t timebase_info;
|
||||
|
||||
static void StartCounter(void)
|
||||
{
|
||||
counter_start = mach_absolute_time();
|
||||
}
|
||||
|
||||
static double GetCounter(void)
|
||||
{
|
||||
ZyanU64 elapsed = mach_absolute_time() - counter_start;
|
||||
|
||||
if (timebase_info.denom == 0)
|
||||
{
|
||||
mach_timebase_info(&timebase_info);
|
||||
}
|
||||
|
||||
return (double)elapsed * timebase_info.numer / timebase_info.denom / 1000000;
|
||||
}
|
||||
|
||||
#elif defined(ZYAN_LINUX) || defined(ZYAN_FREEBSD) || defined(ZYAN_SOLARIS)
|
||||
|
||||
struct timeval t1;
|
||||
|
||||
static void StartCounter(void)
|
||||
{
|
||||
gettimeofday(&t1, NULL);
|
||||
}
|
||||
|
||||
static double GetCounter(void)
|
||||
{
|
||||
struct timeval t2;
|
||||
gettimeofday(&t2, NULL);
|
||||
|
||||
double t = (t2.tv_sec - t1.tv_sec) * 1000.0;
|
||||
return t + (t2.tv_usec - t1.tv_usec) / 1000.0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Process & Thread Priority */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void AdjustProcessAndThreadPriority(void)
|
||||
{
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
if (info.dwNumberOfProcessors > 1)
|
||||
{
|
||||
if (!SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR)1))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sWarning: Could not set thread affinity mask%s\n",
|
||||
CVT100_ERR(ZYAN_VT100SGR_FG_YELLOW), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
}
|
||||
if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sWarning: Could not set process priority class%s\n",
|
||||
CVT100_ERR(ZYAN_VT100SGR_FG_YELLOW), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
}
|
||||
if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sWarning: Could not set thread priority class%s\n",
|
||||
CVT100_ERR(ZYAN_VT100SGR_FG_YELLOW), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(ZYAN_LINUX) || defined(ZYAN_FREEBSD)
|
||||
|
||||
pthread_t thread = pthread_self();
|
||||
|
||||
#if defined(ZYAN_LINUX)
|
||||
cpu_set_t cpus;
|
||||
#else // FreeBSD
|
||||
cpuset_t cpus;
|
||||
#endif
|
||||
|
||||
CPU_ZERO(&cpus);
|
||||
CPU_SET(0, &cpus);
|
||||
if (pthread_setaffinity_np(thread, sizeof(cpus), &cpus))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sWarning: Could not set thread affinity mask%s\n",
|
||||
CVT100_ERR(ZYAN_VT100SGR_FG_YELLOW), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
static ZyanU64 ProcessBuffer(const ZydisDecoder* decoder, const ZydisFormatter* formatter,
|
||||
/* const ZydisCacheTable* cache, */
|
||||
const ZyanU8* buffer, ZyanUSize length, ZyanBool format, ZyanBool tokenize, ZyanBool use_cache)
|
||||
{
|
||||
ZyanU64 count = 0;
|
||||
ZyanUSize offset = 0;
|
||||
ZyanStatus status;
|
||||
ZydisDecodedInstruction instruction_data;
|
||||
ZydisDecodedInstruction* instruction;
|
||||
char format_buffer[256];
|
||||
|
||||
while (length > offset)
|
||||
{
|
||||
if (use_cache)
|
||||
{
|
||||
ZYAN_UNREACHABLE;
|
||||
// status = ZydisDecoderDecodeBufferCached(decoder, cache, buffer + offset,
|
||||
// length - offset, &instruction);
|
||||
} else
|
||||
{
|
||||
status = ZydisDecoderDecodeBuffer(decoder, buffer + offset, length - offset,
|
||||
&instruction_data);
|
||||
instruction = &instruction_data;
|
||||
}
|
||||
|
||||
if (status == ZYDIS_STATUS_NO_MORE_DATA)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!ZYAN_SUCCESS(status))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sUnexpected decoding error. Data: ",
|
||||
CVT100_ERR(COLOR_ERROR));
|
||||
for (ZyanUSize i = 0; i < ZYAN_MIN(ZYDIS_MAX_INSTRUCTION_LENGTH,
|
||||
length - offset); ++i)
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%02X ", (ZyanU8)buffer[offset + i]);
|
||||
}
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%s\n", CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
ZYAN_ASSERT(ZYAN_FALSE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (format)
|
||||
{
|
||||
if (tokenize)
|
||||
{
|
||||
const ZydisFormatterToken* token;
|
||||
ZydisFormatterTokenizeInstruction(formatter, instruction, format_buffer,
|
||||
sizeof(format_buffer), offset, &token);
|
||||
} else
|
||||
{
|
||||
ZydisFormatterFormatInstruction(formatter, instruction, format_buffer,
|
||||
sizeof(format_buffer), offset);
|
||||
}
|
||||
}
|
||||
|
||||
offset += instruction->length;
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void TestPerformance(const ZyanU8* buffer, ZyanUSize length, ZyanBool minimal_mode,
|
||||
ZyanBool format, ZyanBool tokenize, ZyanBool use_cache)
|
||||
{
|
||||
ZydisDecoder decoder;
|
||||
if (!ZYAN_SUCCESS(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64,
|
||||
ZYDIS_ADDRESS_WIDTH_64)))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sFailed to initialize decoder%s\n",
|
||||
CVT100_ERR(COLOR_ERROR), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!ZYAN_SUCCESS(ZydisDecoderEnableMode(&decoder, ZYDIS_DECODER_MODE_MINIMAL, minimal_mode)))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sFailed to adjust decoder-mode%s\n",
|
||||
CVT100_ERR(COLOR_ERROR), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// ZydisCacheTable cache;
|
||||
// if (use_cache && !ZYAN_SUCCESS(ZydisDecoderInitCache(&decoder, &cache)))
|
||||
// {
|
||||
// ZYAN_FPRINTF(ZYAN_STDERR, "%sFailed to initialize decoder-cache%s\n",
|
||||
// CVT100_ERR(COLOR_ERROR), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
// exit(EXIT_FAILURE);
|
||||
// }
|
||||
|
||||
ZydisFormatter formatter;
|
||||
if (format)
|
||||
{
|
||||
if (!ZYAN_SUCCESS(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL)) ||
|
||||
!ZYAN_SUCCESS(ZydisFormatterSetProperty(&formatter,
|
||||
ZYDIS_FORMATTER_PROP_FORCE_SEGMENT, ZYAN_TRUE)) ||
|
||||
!ZYAN_SUCCESS(ZydisFormatterSetProperty(&formatter,
|
||||
ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE)))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sFailed to initialize instruction-formatter%s\n",
|
||||
CVT100_ERR(COLOR_ERROR), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache warmup
|
||||
ProcessBuffer(&decoder, &formatter, /* cache, */ buffer, length, format, tokenize, use_cache);
|
||||
|
||||
// Testing
|
||||
ZyanU64 count = 0;
|
||||
StartCounter();
|
||||
for (ZyanU8 j = 0; j < 100; ++j)
|
||||
{
|
||||
count += ProcessBuffer(&decoder, &formatter, /* cache, */ buffer, length, format,
|
||||
tokenize, use_cache);
|
||||
}
|
||||
const char* color[4];
|
||||
color[0] = minimal_mode ? CVT100_OUT(COLOR_VALUE_G) : CVT100_OUT(COLOR_VALUE_B);
|
||||
color[1] = format ? CVT100_OUT(COLOR_VALUE_G) : CVT100_OUT(COLOR_VALUE_B);
|
||||
color[2] = tokenize ? CVT100_OUT(COLOR_VALUE_G) : CVT100_OUT(COLOR_VALUE_B);
|
||||
color[3] = use_cache ? CVT100_OUT(COLOR_VALUE_G) : CVT100_OUT(COLOR_VALUE_B);
|
||||
ZYAN_PRINTF("Minimal-Mode %s%d%s, Format %s%d%s, Tokenize %s%d%s, Caching %s%d%s, " \
|
||||
"Instructions: %s%6.2fM%s, Time: %s%8.2f%s msec\n",
|
||||
color[0], minimal_mode, CVT100_OUT(COLOR_DEFAULT),
|
||||
color[1], format, CVT100_OUT(COLOR_DEFAULT),
|
||||
color[2], tokenize, CVT100_OUT(COLOR_DEFAULT),
|
||||
color[3], use_cache, CVT100_OUT(COLOR_DEFAULT),
|
||||
CVT100_OUT(COLOR_VALUE_B), (double)count / 1000000, CVT100_OUT(COLOR_DEFAULT),
|
||||
CVT100_OUT(COLOR_VALUE_G), GetCounter(), CVT100_OUT(COLOR_DEFAULT));
|
||||
}
|
||||
|
||||
static void GenerateTestData(FILE* file, ZyanU8 encoding)
|
||||
{
|
||||
ZydisDecoder decoder;
|
||||
if (!ZYAN_SUCCESS(
|
||||
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64)))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sFailed to initialize decoder%s\n", CVT100_ERR(COLOR_ERROR),
|
||||
CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ZyanU8 last = 0;
|
||||
ZyanU32 count = 0;
|
||||
ZydisDecodedInstruction instruction;
|
||||
while (count < 100000)
|
||||
{
|
||||
ZyanU8 data[ZYDIS_MAX_INSTRUCTION_LENGTH];
|
||||
for (int i = 0; i < ZYDIS_MAX_INSTRUCTION_LENGTH; ++i)
|
||||
{
|
||||
data[i] = rand() % 256;
|
||||
}
|
||||
const ZyanU8 offset = rand() % (ZYDIS_MAX_INSTRUCTION_LENGTH - 2);
|
||||
switch (encoding)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
data[offset ] = 0x0F;
|
||||
data[offset + 1] = 0x0F;
|
||||
break;
|
||||
case 2:
|
||||
data[offset ] = 0x8F;
|
||||
break;
|
||||
case 3:
|
||||
data[offset ] = 0xC4;
|
||||
break;
|
||||
case 4:
|
||||
data[offset ] = 0xC5;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
data[offset ] = 0x62;
|
||||
break;
|
||||
default:
|
||||
ZYAN_UNREACHABLE;
|
||||
}
|
||||
if (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, data, sizeof(data), &instruction)))
|
||||
{
|
||||
ZyanBool b = ZYAN_FALSE;
|
||||
switch (encoding)
|
||||
{
|
||||
case 0:
|
||||
b = (instruction.encoding == ZYDIS_INSTRUCTION_ENCODING_LEGACY);
|
||||
break;
|
||||
case 1:
|
||||
b = (instruction.encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW);
|
||||
break;
|
||||
case 2:
|
||||
b = (instruction.encoding == ZYDIS_INSTRUCTION_ENCODING_XOP);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
b = (instruction.encoding == ZYDIS_INSTRUCTION_ENCODING_VEX);
|
||||
break;
|
||||
case 5:
|
||||
b = (instruction.encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX);
|
||||
break;
|
||||
case 6:
|
||||
b = (instruction.encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX);
|
||||
break;
|
||||
default:
|
||||
ZYAN_UNREACHABLE;
|
||||
}
|
||||
if (b)
|
||||
{
|
||||
fwrite(&data[0], sizeof(ZyanU8), instruction.length, file);
|
||||
++count;
|
||||
|
||||
const ZyanU8 p = (ZyanU8)((double)count / 100000 * 100);
|
||||
if (last < p)
|
||||
{
|
||||
last = p;
|
||||
ZYAN_PRINTF("%3.0d%%\n", p);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Entry point */
|
||||
/* ============================================================================================== */
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// Enable VT100 escape sequences on Windows, if the output is not redirected
|
||||
g_vt100_stdout = (ZyanTerminalIsTTY(ZYAN_STDSTREAM_OUT) == ZYAN_STATUS_TRUE) &&
|
||||
ZYAN_SUCCESS(ZyanTerminalEnableVT100(ZYAN_STDSTREAM_OUT));
|
||||
g_vt100_stderr = (ZyanTerminalIsTTY(ZYAN_STDSTREAM_ERR) == ZYAN_STATUS_TRUE) &&
|
||||
ZYAN_SUCCESS(ZyanTerminalEnableVT100(ZYAN_STDSTREAM_ERR));
|
||||
|
||||
if (ZydisGetVersion() != ZYDIS_VERSION)
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sInvalid zydis version%s\n",
|
||||
CVT100_ERR(COLOR_ERROR), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argc < 3 || (ZYAN_STRCMP(argv[1], "-test") && ZYAN_STRCMP(argv[1], "-generate")))
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sUsage: %s -[test|generate] [directory]%s\n",
|
||||
CVT100_ERR(COLOR_ERROR), (argc > 0 ? argv[0] : "PerfTest"),
|
||||
CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ZyanBool generate = ZYAN_FALSE;
|
||||
if (!ZYAN_STRCMP(argv[1], "-generate"))
|
||||
{
|
||||
generate = ZYAN_TRUE;
|
||||
}
|
||||
const char* directory = argv[2];
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char* encoding;
|
||||
const char* filename;
|
||||
} tests[7] =
|
||||
{
|
||||
{ "DEFAULT", "enc_default.dat" },
|
||||
{ "3DNOW" , "enc_3dnow.dat" },
|
||||
{ "XOP" , "enc_xop.dat" },
|
||||
{ "VEX_C4" , "enc_vex_c4.dat" },
|
||||
{ "VEX_C5" , "enc_vex_c5.dat" },
|
||||
{ "EVEX" , "enc_evex.dat" },
|
||||
{ "MVEX" , "enc_mvex.dat" }
|
||||
};
|
||||
|
||||
if (generate)
|
||||
{
|
||||
time_t t;
|
||||
srand((unsigned)time(&t));
|
||||
} else
|
||||
{
|
||||
AdjustProcessAndThreadPriority();
|
||||
}
|
||||
|
||||
for (ZyanU8 i = 0; i < ZYAN_ARRAY_LENGTH(tests); ++i)
|
||||
{
|
||||
FILE* file;
|
||||
|
||||
const ZyanUSize len = strlen(directory);
|
||||
char buf[1024];
|
||||
strncpy(&buf[0], directory, sizeof(buf) - 1);
|
||||
if (generate)
|
||||
{
|
||||
file = fopen(strncat(buf, tests[i].filename, sizeof(buf) - len - 1), "wb");
|
||||
} else
|
||||
{
|
||||
file = fopen(strncat(buf, tests[i].filename, sizeof(buf) - len - 1), "rb");
|
||||
}
|
||||
if (!file)
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR, "%sCould not open file \"%s\": %s%s\n",
|
||||
CVT100_ERR(COLOR_ERROR), &buf[0], strerror(ZYAN_ERRNO),
|
||||
CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (generate)
|
||||
{
|
||||
ZYAN_PRINTF("Generating %s%s%s ...\n", CVT100_OUT(COLOR_VALUE_B), tests[i].encoding,
|
||||
CVT100_OUT(ZYAN_VT100SGR_RESET));
|
||||
GenerateTestData(file, i);
|
||||
} else
|
||||
{
|
||||
fseek(file, 0L, SEEK_END);
|
||||
const long length = ftell(file);
|
||||
void* buffer = malloc(length);
|
||||
if (!buffer)
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR,
|
||||
"%sFailed to allocate %" PRIu64 " bytes on the heap%s\n",
|
||||
CVT100_ERR(COLOR_ERROR), (ZyanU64)length, CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
goto NextFile2;
|
||||
}
|
||||
|
||||
rewind(file);
|
||||
if (fread(buffer, 1, length, file) != (ZyanUSize)length)
|
||||
{
|
||||
ZYAN_FPRINTF(ZYAN_STDERR,
|
||||
"%sCould not read %" PRIu64 " bytes from file \"%s\"%s\n",
|
||||
CVT100_ERR(COLOR_ERROR), (ZyanU64)length, &buf[0],
|
||||
CVT100_ERR(ZYAN_VT100SGR_RESET));
|
||||
goto NextFile1;
|
||||
}
|
||||
|
||||
ZYAN_PRINTF("%sTesting %s%s%s ...\n", CVT100_OUT(ZYAN_VT100SGR_FG_MAGENTA),
|
||||
CVT100_OUT(ZYAN_VT100SGR_FG_BRIGHT_MAGENTA), tests[i].encoding,
|
||||
CVT100_OUT(COLOR_DEFAULT));
|
||||
TestPerformance(buffer, length, ZYAN_TRUE , ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE);
|
||||
TestPerformance(buffer, length, ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE);
|
||||
// TestPerformance(buffer, length, ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE, ZYAN_TRUE);
|
||||
TestPerformance(buffer, length, ZYAN_FALSE, ZYAN_TRUE , ZYAN_FALSE, ZYAN_FALSE);
|
||||
// TestPerformance(buffer, length, ZYAN_FALSE, ZYAN_TRUE , ZYAN_FALSE, ZYAN_TRUE);
|
||||
TestPerformance(buffer, length, ZYAN_FALSE, ZYAN_TRUE , ZYAN_TRUE , ZYAN_FALSE);
|
||||
// TestPerformance(buffer, length, ZYAN_FALSE, ZYAN_TRUE , ZYAN_TRUE , ZYAN_TRUE);
|
||||
ZYAN_PUTS("");
|
||||
|
||||
NextFile1:
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
NextFile2:
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
189
examples/ZydisWinKernel.c
Normal file
189
examples/ZydisWinKernel.c
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Engine (Zydis)
|
||||
|
||||
Original Author : Matthijs Lavrijsen
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Windows kernel mode driver sample.
|
||||
*
|
||||
* This is a Windows kernel mode driver. It links against the kernel mode-compatible version of Zydis.
|
||||
* The driver finds its own entry point and decodes and prints the disassembly of this function.
|
||||
* To view the log, either attach a kernel debugger or use a tool like Sysinternals DebugView.
|
||||
*/
|
||||
|
||||
#include <wdm.h>
|
||||
#include <ntimage.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "Zydis/Zydis.h"
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Forward declarations */
|
||||
/* ============================================================================================== */
|
||||
|
||||
NTKERNELAPI
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlPcToFileHeader(
|
||||
_In_ PVOID PcValue,
|
||||
_Out_ PVOID *BaseOfImage
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
PIMAGE_NT_HEADERS
|
||||
NTAPI
|
||||
RtlImageNtHeader(
|
||||
_In_ PVOID ImageBase
|
||||
);
|
||||
|
||||
#if defined(ZYAN_CLANG) || defined(ZYAN_GNUC)
|
||||
__attribute__((section("INIT")))
|
||||
#endif
|
||||
DRIVER_INITIALIZE
|
||||
DriverEntry;
|
||||
|
||||
#if defined(ALLOC_PRAGMA) && !(defined(ZYAN_CLANG) || defined(ZYAN_GNUC))
|
||||
#pragma alloc_text(INIT, DriverEntry)
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Helper functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
VOID
|
||||
Print(
|
||||
_In_ PCCH Format,
|
||||
_In_ ...
|
||||
)
|
||||
{
|
||||
CHAR message[512];
|
||||
va_list argList;
|
||||
va_start(argList, Format);
|
||||
const int n = _vsnprintf_s(message, sizeof(message), sizeof(message) - 1, Format, argList);
|
||||
message[n] = '\0';
|
||||
vDbgPrintExWithPrefix("[ZYDIS] ", DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, message, argList);
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Entry point */
|
||||
/* ============================================================================================== */
|
||||
|
||||
_Use_decl_annotations_
|
||||
NTSTATUS
|
||||
DriverEntry(
|
||||
_In_ PDRIVER_OBJECT DriverObject,
|
||||
_In_ PUNICODE_STRING RegistryPath
|
||||
)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
UNREFERENCED_PARAMETER(RegistryPath);
|
||||
|
||||
if (ZydisGetVersion() != ZYDIS_VERSION)
|
||||
{
|
||||
Print("Invalid zydis version\n");
|
||||
return STATUS_UNKNOWN_REVISION;
|
||||
}
|
||||
|
||||
// Get the driver's image base and PE headers
|
||||
ULONG_PTR imageBase;
|
||||
RtlPcToFileHeader((PVOID)DriverObject->DriverInit, (PVOID*)&imageBase);
|
||||
if (imageBase == 0)
|
||||
return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
|
||||
const PIMAGE_NT_HEADERS ntHeaders = RtlImageNtHeader((PVOID)imageBase);
|
||||
if (ntHeaders == NULL)
|
||||
return STATUS_INVALID_IMAGE_FORMAT;
|
||||
|
||||
// Get the section headers of the INIT section
|
||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
|
||||
PIMAGE_SECTION_HEADER initSection = NULL;
|
||||
for (USHORT i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i)
|
||||
{
|
||||
if (memcmp(section->Name, "INIT", sizeof("INIT") - 1) == 0)
|
||||
{
|
||||
initSection = section;
|
||||
break;
|
||||
}
|
||||
section++;
|
||||
}
|
||||
if (initSection == NULL)
|
||||
return STATUS_NOT_FOUND;
|
||||
|
||||
// Get the RVAs of the entry point and import directory. If the import directory lies within the INIT section,
|
||||
// stop disassembling when its address is reached. Otherwise, disassemble until the end of the INIT section.
|
||||
const ULONG entryPointRva = (ULONG)((ULONG_PTR)DriverObject->DriverInit - imageBase);
|
||||
const ULONG importDirRva = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
||||
SIZE_T length = initSection->VirtualAddress + initSection->SizeOfRawData - entryPointRva;
|
||||
if (importDirRva > entryPointRva && importDirRva > initSection->VirtualAddress &&
|
||||
importDirRva < initSection->VirtualAddress + initSection->SizeOfRawData)
|
||||
length = importDirRva - entryPointRva;
|
||||
|
||||
Print("Driver image base: 0x%p, size: 0x%X\n", (PVOID)imageBase, ntHeaders->OptionalHeader.SizeOfImage);
|
||||
Print("Entry point RVA: 0x%X (0x%p)\n", entryPointRva, DriverObject->DriverInit);
|
||||
|
||||
// Initialize Zydis decoder and formatter
|
||||
ZydisDecoder decoder;
|
||||
#ifdef _M_AMD64
|
||||
if (!ZYAN_SUCCESS(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64)))
|
||||
#else
|
||||
if (!ZYAN_SUCCESS(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_COMPAT_32, ZYDIS_ADDRESS_WIDTH_32)))
|
||||
#endif
|
||||
return STATUS_DRIVER_INTERNAL_ERROR;
|
||||
|
||||
ZydisFormatter formatter;
|
||||
if (!ZYAN_SUCCESS(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL)))
|
||||
return STATUS_DRIVER_INTERNAL_ERROR;
|
||||
|
||||
SIZE_T readOffset = 0;
|
||||
ZydisDecodedInstruction instruction;
|
||||
ZyanStatus status;
|
||||
CHAR printBuffer[128];
|
||||
|
||||
// Start the decode loop
|
||||
while ((status = ZydisDecoderDecodeBuffer(&decoder, (PVOID)(imageBase + entryPointRva + readOffset),
|
||||
length - readOffset, &instruction)) != ZYDIS_STATUS_NO_MORE_DATA)
|
||||
{
|
||||
NT_ASSERT(ZYAN_SUCCESS(status));
|
||||
if (!ZYAN_SUCCESS(status))
|
||||
{
|
||||
readOffset++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Format and print the instruction
|
||||
const ZyanU64 instrAddress = (ZyanU64)(imageBase + entryPointRva + readOffset);
|
||||
ZydisFormatterFormatInstruction(
|
||||
&formatter, &instruction, printBuffer, sizeof(printBuffer), instrAddress);
|
||||
Print("+%-4X 0x%-16llX\t\t%hs\n", (ULONG)readOffset, instrAddress, printBuffer);
|
||||
|
||||
readOffset += instruction.length;
|
||||
}
|
||||
|
||||
// Return an error status so that the driver does not have to be unloaded after running.
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
Loading…
Add table
Add a link
Reference in a new issue