mirror of https://github.com/x64dbg/zydis
Added tool for testing Zydis against CPU behaviour (Intel PIN)
This commit is contained in:
parent
5b63557f3c
commit
cbc9460547
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
#ifndef ZYDIS_EXPORT_H
|
||||||
|
#define ZYDIS_EXPORT_H
|
||||||
|
|
||||||
|
#ifdef ZYDIS_STATIC_DEFINE
|
||||||
|
# define ZYDIS_EXPORT
|
||||||
|
# define ZYDIS_NO_EXPORT
|
||||||
|
#else
|
||||||
|
# ifndef ZYDIS_EXPORT
|
||||||
|
# ifdef Zydis_EXPORTS
|
||||||
|
/* We are building this library */
|
||||||
|
# define ZYDIS_EXPORT
|
||||||
|
# else
|
||||||
|
/* We are using this library */
|
||||||
|
# define ZYDIS_EXPORT
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef ZYDIS_NO_EXPORT
|
||||||
|
# define ZYDIS_NO_EXPORT
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZYDIS_DEPRECATED
|
||||||
|
# define ZYDIS_DEPRECATED __attribute__ ((__deprecated__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZYDIS_DEPRECATED_EXPORT
|
||||||
|
# define ZYDIS_DEPRECATED_EXPORT ZYDIS_EXPORT ZYDIS_DEPRECATED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZYDIS_DEPRECATED_NO_EXPORT
|
||||||
|
# define ZYDIS_DEPRECATED_NO_EXPORT ZYDIS_NO_EXPORT ZYDIS_DEPRECATED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFINE_NO_DEPRECATED 0
|
||||||
|
#if DEFINE_NO_DEPRECATED
|
||||||
|
# define ZYDIS_NO_DEPRECATED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,286 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 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 "pin.H"
|
||||||
|
#include "xed-interface.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
#include <set>
|
||||||
|
#include <Zydis/Zydis.h>
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* TLS struct */
|
||||||
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
struct ThreadData
|
||||||
|
{
|
||||||
|
CONTEXT ctx;
|
||||||
|
ZydisInstructionDecoder decoder;
|
||||||
|
|
||||||
|
ThreadData()
|
||||||
|
{
|
||||||
|
ZydisDecoderInitInstructionDecoderEx(
|
||||||
|
&decoder, ZYDIS_DISASSEMBLER_MODE_64BIT, NULL, 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Global variables */
|
||||||
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
TLS_KEY tls_key;
|
||||||
|
std::ostream* out = &cerr;
|
||||||
|
|
||||||
|
PIN_LOCK unique_iforms_lock;
|
||||||
|
std::set<xed_iform_enum_t> unique_iforms;
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Tables */
|
||||||
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
struct RegMapping
|
||||||
|
{
|
||||||
|
REG pin;
|
||||||
|
ZydisRegister zy;
|
||||||
|
};
|
||||||
|
|
||||||
|
RegMapping reg_mapping[] = {
|
||||||
|
// 64-bit GP register
|
||||||
|
{REG_RAX, ZYDIS_REGISTER_RAX},
|
||||||
|
{REG_RBX, ZYDIS_REGISTER_RBX},
|
||||||
|
{REG_RCX, ZYDIS_REGISTER_RCX},
|
||||||
|
{REG_RDX, ZYDIS_REGISTER_RDX},
|
||||||
|
{REG_RSP, ZYDIS_REGISTER_RSP},
|
||||||
|
{REG_RBP, ZYDIS_REGISTER_RBP},
|
||||||
|
{REG_RSI, ZYDIS_REGISTER_RSI},
|
||||||
|
{REG_RDI, ZYDIS_REGISTER_RDI},
|
||||||
|
{REG_R8, ZYDIS_REGISTER_R8 },
|
||||||
|
{REG_R9, ZYDIS_REGISTER_R9 },
|
||||||
|
{REG_R10, ZYDIS_REGISTER_R10},
|
||||||
|
{REG_R11, ZYDIS_REGISTER_R11},
|
||||||
|
{REG_R12, ZYDIS_REGISTER_R12},
|
||||||
|
{REG_R13, ZYDIS_REGISTER_R13},
|
||||||
|
{REG_R14, ZYDIS_REGISTER_R14},
|
||||||
|
{REG_R15, ZYDIS_REGISTER_R15},
|
||||||
|
|
||||||
|
// Segment registers
|
||||||
|
{REG_SEG_ES, ZYDIS_REGISTER_ES},
|
||||||
|
{REG_SEG_SS, ZYDIS_REGISTER_SS},
|
||||||
|
{REG_SEG_SS, ZYDIS_REGISTER_SS},
|
||||||
|
{REG_SEG_CS, ZYDIS_REGISTER_CS},
|
||||||
|
{REG_SEG_DS, ZYDIS_REGISTER_DS},
|
||||||
|
{REG_SEG_FS, ZYDIS_REGISTER_FS},
|
||||||
|
{REG_SEG_GS, ZYDIS_REGISTER_GS},
|
||||||
|
|
||||||
|
// Mask registers
|
||||||
|
{REG_K0, ZYDIS_REGISTER_K0},
|
||||||
|
{REG_K1, ZYDIS_REGISTER_K1},
|
||||||
|
{REG_K2, ZYDIS_REGISTER_K2},
|
||||||
|
{REG_K3, ZYDIS_REGISTER_K3},
|
||||||
|
{REG_K4, ZYDIS_REGISTER_K4},
|
||||||
|
{REG_K5, ZYDIS_REGISTER_K5},
|
||||||
|
{REG_K6, ZYDIS_REGISTER_K6},
|
||||||
|
{REG_K7, ZYDIS_REGISTER_K7},
|
||||||
|
|
||||||
|
// TODO: XMM, YMM, ZMM, ST, TR
|
||||||
|
|
||||||
|
// Special registers
|
||||||
|
{REG_MXCSR, ZYDIS_REGISTER_MXCSR},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Command line switches */
|
||||||
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
KNOB<string> knob_out_file(
|
||||||
|
KNOB_MODE_WRITEONCE, "pintool", "o", "", "Output file name"
|
||||||
|
);
|
||||||
|
|
||||||
|
KNOB<bool> know_unique_iform(
|
||||||
|
KNOB_MODE_WRITEONCE, "pintool", "unique_iform", "0",
|
||||||
|
"Only instrument one instruction per iform"
|
||||||
|
);
|
||||||
|
|
||||||
|
KNOB<bool> omit_op_checks(
|
||||||
|
KNOB_MODE_WRITEONCE, "pintool", "omit_op_checks", "0",
|
||||||
|
"Skip verification of operand write assumptions"
|
||||||
|
);
|
||||||
|
|
||||||
|
KNOB<bool> omit_flag_checks(
|
||||||
|
KNOB_MODE_WRITEONCE, "pintool", "omit_flag_checks", "1",
|
||||||
|
"Skip verification of flag write assumptions"
|
||||||
|
);
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Instrumentation callbacks */
|
||||||
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
VOID PIN_FAST_ANALYSIS_CALL pre_ins_cb(THREADID tid, const CONTEXT* ctx)
|
||||||
|
{
|
||||||
|
ThreadData *tls = static_cast<ThreadData*>(PIN_GetThreadData(tls_key, tid));
|
||||||
|
PIN_SaveContext(ctx, &tls->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID PIN_FAST_ANALYSIS_CALL post_ins_cb(THREADID tid, const CONTEXT* post_ctx)
|
||||||
|
{
|
||||||
|
ThreadData *tls = static_cast<ThreadData*>(PIN_GetThreadData(tls_key, tid));
|
||||||
|
|
||||||
|
// Get IPs.
|
||||||
|
ADDRINT pre_ip = PIN_GetContextReg(&tls->ctx, REG_INST_PTR);
|
||||||
|
ADDRINT post_ip = PIN_GetContextReg(post_ctx, REG_INST_PTR);
|
||||||
|
|
||||||
|
// If the IP didn't change, we're probably dealing with a rep.
|
||||||
|
// Skip instruction until last execution where fallthrough kicks in.
|
||||||
|
ADDRINT ip_diff = post_ip - pre_ip;
|
||||||
|
if (!ip_diff) return;
|
||||||
|
|
||||||
|
// Disassemble previously executed instruction.
|
||||||
|
ZydisMemoryInput input;
|
||||||
|
ZydisInputInitMemoryInput(&input, (void*)pre_ip, 15);
|
||||||
|
ZydisDecoderSetInput(&tls->decoder, (ZydisCustomInput*)&input);
|
||||||
|
|
||||||
|
ZydisInstructionInfo insn_info;
|
||||||
|
ZydisStatus decode_status = ZydisDecoderDecodeNextInstruction(
|
||||||
|
&tls->decoder, &insn_info
|
||||||
|
);
|
||||||
|
|
||||||
|
// Can we decode it?
|
||||||
|
if (!ZYDIS_SUCCESS(decode_status)) {
|
||||||
|
*out << "Decoding failure" << endl;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does the length look like what we expected?
|
||||||
|
if (insn_info.length != ip_diff) {
|
||||||
|
*out << "Instruction length mismatch (expected "
|
||||||
|
<< dec << ip_diff << ", got " << (int)insn_info.length
|
||||||
|
<< ')' << endl;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analyze operand effects.
|
||||||
|
if (!omit_op_checks) {
|
||||||
|
for (const RegMapping* map = reg_mapping
|
||||||
|
; map < reg_mapping + sizeof reg_mapping / sizeof reg_mapping[0]
|
||||||
|
; ++map) {
|
||||||
|
|
||||||
|
ADDRINT pre_reg_val = PIN_GetContextReg(&tls->ctx, map->pin);
|
||||||
|
ADDRINT post_reg_val = PIN_GetContextReg(post_ctx, map->pin);
|
||||||
|
|
||||||
|
// Did the instruction touch this register?
|
||||||
|
if (pre_reg_val != post_reg_val) {
|
||||||
|
*out << "Reg value changed ("
|
||||||
|
<< ZydisRegisterGetString(map->zy)
|
||||||
|
<< ")!" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analyze flag effects.
|
||||||
|
if (!omit_flag_checks) {
|
||||||
|
ADDRINT prev_flags = PIN_GetContextReg(&tls->ctx, REG_GFLAGS);
|
||||||
|
ADDRINT new_flags = PIN_GetContextReg(post_ctx, REG_GFLAGS);
|
||||||
|
ADDRINT changed_flags = prev_flags ^ new_flags;
|
||||||
|
if (changed_flags) {
|
||||||
|
// TODO: implement once flag infos are available.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
// Always print raw bytes on error.
|
||||||
|
*out << "Raw bytes: ";
|
||||||
|
for (size_t i = 0; i < 15; ++i) {
|
||||||
|
*out << setfill('0') << setw(2) << hex
|
||||||
|
<< (int)((uint8_t*)pre_ip)[i] << ' ';
|
||||||
|
}
|
||||||
|
*out << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID instruction(INS ins, VOID *v)
|
||||||
|
{
|
||||||
|
if (!INS_HasFallThrough(ins)) return;
|
||||||
|
|
||||||
|
xed_decoded_inst_t* xed = INS_XedDec(ins);
|
||||||
|
xed_iform_enum_t iform = xed_decoded_inst_get_iform_enum(xed);
|
||||||
|
|
||||||
|
if (know_unique_iform.Value()) {
|
||||||
|
PIN_GetLock(&unique_iforms_lock, 0);
|
||||||
|
if (unique_iforms.find(iform) != unique_iforms.end()) {
|
||||||
|
PIN_ReleaseLock(&unique_iforms_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unique_iforms.insert(iform);
|
||||||
|
*out << iform << endl;
|
||||||
|
PIN_ReleaseLock(&unique_iforms_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
INS_InsertCall(
|
||||||
|
ins, IPOINT_BEFORE, (AFUNPTR)&pre_ins_cb,
|
||||||
|
IARG_FAST_ANALYSIS_CALL, IARG_THREAD_ID, IARG_CONST_CONTEXT,
|
||||||
|
IARG_END
|
||||||
|
);
|
||||||
|
INS_InsertCall(
|
||||||
|
ins, IPOINT_AFTER, (AFUNPTR)&post_ins_cb,
|
||||||
|
IARG_FAST_ANALYSIS_CALL, IARG_THREAD_ID, IARG_CONST_CONTEXT,
|
||||||
|
IARG_END
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID thread_start(THREADID tid, CONTEXT *ctx, INT32 flags, VOID* v)
|
||||||
|
{
|
||||||
|
ThreadData* tls = new ThreadData;
|
||||||
|
PIN_SetThreadData(tls_key, tls, tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (PIN_Init(argc, argv)) {
|
||||||
|
cerr << KNOB_BASE::StringKnobSummary() << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open output file.
|
||||||
|
string file_name = knob_out_file.Value();
|
||||||
|
if (!file_name.empty()) {
|
||||||
|
out = new std::ofstream(file_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init TLS.
|
||||||
|
tls_key = PIN_CreateThreadDataKey(0);
|
||||||
|
PIN_InitLock(&unique_iforms_lock);
|
||||||
|
|
||||||
|
// Register hooks.
|
||||||
|
PIN_AddThreadStartFunction(&thread_start, NULL);
|
||||||
|
INS_AddInstrumentFunction(&instruction, NULL);
|
||||||
|
|
||||||
|
// Start the program, never returns.
|
||||||
|
PIN_StartProgram();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
|
@ -0,0 +1,21 @@
|
||||||
|
##############################################################
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE!
|
||||||
|
#
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
# If the tool is built out of the kit, PIN_ROOT must be specified in the make invocation and point to the kit root.
|
||||||
|
ifdef PIN_ROOT
|
||||||
|
CONFIG_ROOT := $(PIN_ROOT)/source/tools/Config
|
||||||
|
else
|
||||||
|
CONFIG_ROOT := ../Config
|
||||||
|
endif
|
||||||
|
include $(CONFIG_ROOT)/makefile.config
|
||||||
|
include makefile.rules
|
||||||
|
include $(TOOLS_ROOT)/Config/makefile.default.rules
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE!
|
||||||
|
#
|
||||||
|
##############################################################
|
|
@ -0,0 +1,89 @@
|
||||||
|
##############################################################
|
||||||
|
#
|
||||||
|
# This file includes all the test targets as well as all the
|
||||||
|
# non-default build rules and test recipes.
|
||||||
|
#
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
#
|
||||||
|
# Test targets
|
||||||
|
#
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
###### Place all generic definitions here ######
|
||||||
|
|
||||||
|
# This defines tests which run tools of the same name. This is simply for convenience to avoid
|
||||||
|
# defining the test name twice (once in TOOL_ROOTS and again in TEST_ROOTS).
|
||||||
|
# Tests defined here should not be defined in TOOL_ROOTS and TEST_ROOTS.
|
||||||
|
TEST_TOOL_ROOTS := ZydisTestTool
|
||||||
|
|
||||||
|
OBJECT_ROOTS += \
|
||||||
|
zydis/src/Decoder \
|
||||||
|
zydis/src/Formatter \
|
||||||
|
zydis/src/Input \
|
||||||
|
zydis/src/InstructionDetails \
|
||||||
|
zydis/src/InstructionTable \
|
||||||
|
zydis/src/Mnemonic \
|
||||||
|
zydis/src/Register \
|
||||||
|
zydis/src/Utils \
|
||||||
|
zydis/src/Zydis
|
||||||
|
|
||||||
|
# This defines the tests to be run that were not already defined in TEST_TOOL_ROOTS.
|
||||||
|
TEST_ROOTS :=
|
||||||
|
|
||||||
|
# This defines the tools which will be run during the the tests, and were not already defined in
|
||||||
|
# TEST_TOOL_ROOTS.
|
||||||
|
TOOL_ROOTS :=
|
||||||
|
|
||||||
|
# This defines the static analysis tools which will be run during the the tests. They should not
|
||||||
|
# be defined in TEST_TOOL_ROOTS. If a test with the same name exists, it should be defined in
|
||||||
|
# TEST_ROOTS.
|
||||||
|
# Note: Static analysis tools are in fact executables linked with the Pin Static Analysis Library.
|
||||||
|
# This library provides a subset of the Pin APIs which allows the tool to perform static analysis
|
||||||
|
# of an application or dll. Pin itself is not used when this tool runs.
|
||||||
|
SA_TOOL_ROOTS :=
|
||||||
|
|
||||||
|
# This defines all the applications that will be run during the tests.
|
||||||
|
APP_ROOTS :=
|
||||||
|
|
||||||
|
# This defines any additional object files that need to be compiled.
|
||||||
|
OBJECT_ROOTS :=
|
||||||
|
|
||||||
|
# This defines any additional dlls (shared objects), other than the pintools, that need to be compiled.
|
||||||
|
DLL_ROOTS :=
|
||||||
|
|
||||||
|
# This defines any static libraries (archives), that need to be built.
|
||||||
|
LIB_ROOTS :=
|
||||||
|
|
||||||
|
###### Define the sanity subset ######
|
||||||
|
|
||||||
|
# This defines the list of tests that should run in sanity. It should include all the tests listed in
|
||||||
|
# TEST_TOOL_ROOTS and TEST_ROOTS excluding only unstable tests.
|
||||||
|
SANITY_SUBSET := $(TEST_TOOL_ROOTS) $(TEST_ROOTS)
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
#
|
||||||
|
# Test recipes
|
||||||
|
#
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
# This section contains recipes for tests other than the default.
|
||||||
|
# See makefile.default.rules for the default test rules.
|
||||||
|
# All tests in this section should adhere to the naming convention: <testname>.test
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
#
|
||||||
|
# Build rules
|
||||||
|
#
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
ADDITIONAL_INCLUDES := -Izydis/include -I.
|
||||||
|
TOOL_CFLAGS += $(ADDITIONAL_INCLUDES)
|
||||||
|
TOOL_CXXFLAGS += $(ADDITIONAL_INCLUDES)
|
||||||
|
|
||||||
|
$(OBJDIR)ZydisTestTool$(PINTOOL_SUFFIX): $(OBJDIR)ZydisTestTool$(OBJ_SUFFIX) $(OBJDIR)zydis/src/Decoder$(OBJ_SUFFIX) $(OBJDIR)zydis/src/Formatter$(OBJ_SUFFIX) $(OBJDIR)zydis/src/Input$(OBJ_SUFFIX) $(OBJDIR)zydis/src/InstructionDetails$(OBJ_SUFFIX) $(OBJDIR)zydis/src/InstructionTable$(OBJ_SUFFIX) $(OBJDIR)zydis/src/Mnemonic$(OBJ_SUFFIX) $(OBJDIR)zydis/src/Register$(OBJ_SUFFIX) $(OBJDIR)zydis/src/Utils$(OBJ_SUFFIX) $(OBJDIR)zydis/src/Zydis$(OBJ_SUFFIX)
|
||||||
|
$(LINKER) $(TOOL_LDFLAGS) $(LINK_EXE)$@ $^ $(TOOL_LPATHS) $(TOOL_LIBS)
|
Loading…
Reference in New Issue