API: support SKIPDATA option (off by default)
This commit is contained in:
parent
b6961b6ceb
commit
d3ffe37c47
121
cs.c
121
cs.c
|
@ -17,6 +17,9 @@
|
||||||
#define INSN_CACHE_SIZE 8
|
#define INSN_CACHE_SIZE 8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// default SKIPDATA mnemonic
|
||||||
|
#define SKIPDATA_MNEM ".db"
|
||||||
|
|
||||||
cs_err (*arch_init[MAX_ARCH])(cs_struct *) = { NULL };
|
cs_err (*arch_init[MAX_ARCH])(cs_struct *) = { NULL };
|
||||||
cs_err (*arch_option[MAX_ARCH]) (cs_struct *, cs_opt_type, size_t value) = { NULL };
|
cs_err (*arch_option[MAX_ARCH]) (cs_struct *, cs_opt_type, size_t value) = { NULL };
|
||||||
void (*arch_destroy[MAX_ARCH]) (cs_struct *) = { NULL };
|
void (*arch_destroy[MAX_ARCH]) (cs_struct *) = { NULL };
|
||||||
|
@ -187,6 +190,9 @@ cs_err cs_open(cs_arch arch, cs_mode mode, csh *handle)
|
||||||
// by default, do not break instruction into details
|
// by default, do not break instruction into details
|
||||||
ud->detail = CS_OPT_OFF;
|
ud->detail = CS_OPT_OFF;
|
||||||
|
|
||||||
|
// default skipdata setup
|
||||||
|
ud->skipdata_setup.mnemonic = SKIPDATA_MNEM;
|
||||||
|
|
||||||
cs_err err = arch_init[ud->arch](ud);
|
cs_err err = arch_init[ud->arch](ud);
|
||||||
if (err) {
|
if (err) {
|
||||||
cs_mem_free(ud);
|
cs_mem_free(ud);
|
||||||
|
@ -287,6 +293,27 @@ static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCI
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// how many bytes will we skip when encountering data (CS_OPT_SKIPDATA)?
|
||||||
|
static uint8_t skipdata_size(cs_struct *handle)
|
||||||
|
{
|
||||||
|
switch(handle->arch) {
|
||||||
|
default:
|
||||||
|
// should never reach
|
||||||
|
return -1;
|
||||||
|
case CS_ARCH_ARM:
|
||||||
|
case CS_ARCH_ARM64:
|
||||||
|
case CS_ARCH_MIPS:
|
||||||
|
case CS_ARCH_PPC:
|
||||||
|
case CS_ARCH_SPARC:
|
||||||
|
case CS_ARCH_SYSZ:
|
||||||
|
// skip 2 bytes due to instruction alignment
|
||||||
|
return 2;
|
||||||
|
case CS_ARCH_X86:
|
||||||
|
// X86 has no restriction on instruction alignment
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cs_err cs_option(csh ud, cs_opt_type type, size_t value)
|
cs_err cs_option(csh ud, cs_opt_type type, size_t value)
|
||||||
{
|
{
|
||||||
archs_enable();
|
archs_enable();
|
||||||
|
@ -309,9 +336,25 @@ cs_err cs_option(csh ud, cs_opt_type type, size_t value)
|
||||||
if (!handle)
|
if (!handle)
|
||||||
return CS_ERR_CSH;
|
return CS_ERR_CSH;
|
||||||
|
|
||||||
if (type == CS_OPT_DETAIL) {
|
switch(type) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case CS_OPT_DETAIL:
|
||||||
handle->detail = value;
|
handle->detail = value;
|
||||||
return CS_ERR_OK;
|
return CS_ERR_OK;
|
||||||
|
case CS_OPT_SKIPDATA:
|
||||||
|
handle->skipdata = (value == CS_OPT_ON);
|
||||||
|
if (handle->skipdata) {
|
||||||
|
if (handle->skipdata_size == 0) {
|
||||||
|
// set the default skipdata size
|
||||||
|
handle->skipdata_size = skipdata_size(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CS_ERR_OK;
|
||||||
|
case CS_OPT_SKIPDATA_SETUP:
|
||||||
|
if (value)
|
||||||
|
handle->skipdata_setup = *((cs_opt_skipdata *)value);
|
||||||
|
return CS_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return arch_option[handle->arch](handle, type, value);
|
return arch_option[handle->arch](handle, type, value);
|
||||||
|
@ -330,6 +373,26 @@ static cs_insn *get_prev_insn(cs_insn *cache, unsigned int f, void *total, size_
|
||||||
return &cache[f - 1];
|
return &cache[f - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void skipdata_opstr(char *opstr, const uint8_t *buffer, size_t size)
|
||||||
|
{
|
||||||
|
char *p = opstr;
|
||||||
|
int len;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!size) {
|
||||||
|
opstr[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = sprintf(p, "0x%02x", buffer[0]);
|
||||||
|
p+= len;
|
||||||
|
|
||||||
|
for(i = 1; i < size; i++) {
|
||||||
|
len = sprintf(p, ", 0x%02x", buffer[i]);
|
||||||
|
p+= len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dynamicly allocate memory to contain disasm insn
|
// dynamicly allocate memory to contain disasm insn
|
||||||
// NOTE: caller must free() the allocated memory itself to avoid memory leaking
|
// NOTE: caller must free() the allocated memory itself to avoid memory leaking
|
||||||
size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
|
size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
|
||||||
|
@ -343,6 +406,8 @@ size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset,
|
||||||
void *total = NULL;
|
void *total = NULL;
|
||||||
size_t total_size = 0;
|
size_t total_size = 0;
|
||||||
bool r;
|
bool r;
|
||||||
|
void *tmp;
|
||||||
|
size_t skipdata_bytes;
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
// FIXME: how to handle this case:
|
// FIXME: how to handle this case:
|
||||||
|
@ -384,11 +449,8 @@ size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset,
|
||||||
|
|
||||||
if (!handle->check_combine || !handle->check_combine(handle, &insn_cache[f])) {
|
if (!handle->check_combine || !handle->check_combine(handle, &insn_cache[f])) {
|
||||||
f++;
|
f++;
|
||||||
|
|
||||||
if (f == ARR_SIZE(insn_cache)) {
|
if (f == ARR_SIZE(insn_cache)) {
|
||||||
// resize total to contain newly disasm insns
|
// resize total to contain newly disasm insns
|
||||||
void *tmp;
|
|
||||||
|
|
||||||
total_size += (sizeof(cs_insn) * INSN_CACHE_SIZE);
|
total_size += (sizeof(cs_insn) * INSN_CACHE_SIZE);
|
||||||
tmp = cs_mem_realloc(total, total_size);
|
tmp = cs_mem_realloc(total, total_size);
|
||||||
if (tmp == NULL) { // insufficient memory
|
if (tmp == NULL) { // insufficient memory
|
||||||
|
@ -436,8 +498,57 @@ size_t cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// encounter a broken instruction
|
// encounter a broken instruction
|
||||||
// XXX: TODO: JOXEAN continue here
|
// if there is no request to skip data, or remaining data is too small,
|
||||||
|
// then bail out
|
||||||
|
if (!handle->skipdata || handle->skipdata_size > size)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (handle->skipdata_setup.callback) {
|
||||||
|
skipdata_bytes = handle->skipdata_setup.callback(offset,
|
||||||
|
handle->skipdata_setup.user_data);
|
||||||
|
if (skipdata_bytes > size)
|
||||||
|
// remaining data is not enough
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!skipdata_bytes)
|
||||||
|
// user requested not to skip data, so bail out
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
skipdata_bytes = handle->skipdata_size;
|
||||||
|
|
||||||
|
// we have to skip some amount of data, depending on arch & mode
|
||||||
|
insn_cache[f].id = 0; // invalid ID for this "data" instruction
|
||||||
|
insn_cache[f].address = offset;
|
||||||
|
insn_cache[f].size = skipdata_bytes;
|
||||||
|
memcpy(insn_cache[f].bytes, buffer, skipdata_bytes);
|
||||||
|
strncpy(insn_cache[f].mnemonic, handle->skipdata_setup.mnemonic,
|
||||||
|
sizeof(insn_cache[f].mnemonic) - 1);
|
||||||
|
skipdata_opstr(insn_cache[f].op_str, buffer, skipdata_bytes);
|
||||||
|
insn_cache[f].detail = NULL;
|
||||||
|
|
||||||
|
f++;
|
||||||
|
if (f == ARR_SIZE(insn_cache)) {
|
||||||
|
// resize total to contain newly disasm insns
|
||||||
|
|
||||||
|
total_size += (sizeof(cs_insn) * INSN_CACHE_SIZE);
|
||||||
|
tmp = cs_mem_realloc(total, total_size);
|
||||||
|
if (tmp == NULL) { // insufficient memory
|
||||||
|
cs_mem_free(total);
|
||||||
|
handle->errnum = CS_ERR_MEM;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
total = tmp;
|
||||||
|
memcpy((void*)((uintptr_t)total + total_size - sizeof(insn_cache)), insn_cache, sizeof(insn_cache));
|
||||||
|
|
||||||
|
// reset f back to 0
|
||||||
|
f = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += skipdata_bytes;
|
||||||
|
size -= skipdata_bytes;
|
||||||
|
offset += skipdata_bytes;
|
||||||
|
c++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,9 @@ struct cs_struct {
|
||||||
CombineInsn_t combine;
|
CombineInsn_t combine;
|
||||||
GetRegisterName_t get_regname;
|
GetRegisterName_t get_regname;
|
||||||
uint8_t prev_prefix; // save previous prefix for combining instructions - X86 only.
|
uint8_t prev_prefix; // save previous prefix for combining instructions - X86 only.
|
||||||
|
bool skipdata; // set this to True if we skip data when disassembling
|
||||||
|
uint8_t skipdata_size; // how many bytes to skip
|
||||||
|
cs_opt_skipdata skipdata_setup; // user-defined skipdata setup
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_ARCH 8
|
#define MAX_ARCH 8
|
||||||
|
|
|
@ -90,18 +90,45 @@ typedef enum cs_opt_type {
|
||||||
CS_OPT_DETAIL, // Break down instruction structure into details
|
CS_OPT_DETAIL, // Break down instruction structure into details
|
||||||
CS_OPT_MODE, // Change engine's mode at run-time
|
CS_OPT_MODE, // Change engine's mode at run-time
|
||||||
CS_OPT_MEM, // User-defined dynamic memory related functions
|
CS_OPT_MEM, // User-defined dynamic memory related functions
|
||||||
|
CS_OPT_SKIPDATA, // Skip data when disassembling
|
||||||
|
CS_OPT_SKIPDATA_SETUP, // Setup user-defined function for SKIPDATA option
|
||||||
} cs_opt_type;
|
} cs_opt_type;
|
||||||
|
|
||||||
// Runtime option value (associated with option type above)
|
// Runtime option value (associated with option type above)
|
||||||
typedef enum cs_opt_value {
|
typedef enum cs_opt_value {
|
||||||
CS_OPT_OFF = 0, // Turn OFF an option - default option for CS_OPT_DETAIL.
|
CS_OPT_OFF = 0, // Turn OFF an option - default option of CS_OPT_DETAIL, CS_OPT_SKIPDATA.
|
||||||
CS_OPT_ON = 3, // Turn ON an option (CS_OPT_DETAIL).
|
CS_OPT_ON = 3, // Turn ON an option (CS_OPT_DETAIL, CS_OPT_SKIPDATA).
|
||||||
CS_OPT_SYNTAX_DEFAULT = 0, // Default asm syntax (CS_OPT_SYNTAX).
|
CS_OPT_SYNTAX_DEFAULT = 0, // Default asm syntax (CS_OPT_SYNTAX).
|
||||||
CS_OPT_SYNTAX_INTEL, // X86 Intel asm syntax - default on X86 (CS_OPT_SYNTAX).
|
CS_OPT_SYNTAX_INTEL, // X86 Intel asm syntax - default on X86 (CS_OPT_SYNTAX).
|
||||||
CS_OPT_SYNTAX_ATT, // X86 ATT asm syntax (CS_OPT_SYNTAX).
|
CS_OPT_SYNTAX_ATT, // X86 ATT asm syntax (CS_OPT_SYNTAX).
|
||||||
CS_OPT_SYNTAX_NOREGNAME, // Prints register name with only number (CS_OPT_SYNTAX)
|
CS_OPT_SYNTAX_NOREGNAME, // Prints register name with only number (CS_OPT_SYNTAX)
|
||||||
} cs_opt_value;
|
} cs_opt_value;
|
||||||
|
|
||||||
|
// User-defined callback function for SKIPDATA option
|
||||||
|
// @offset: offset of the input buffer passed to cs_disasm_ex().
|
||||||
|
// This indicates the position of data Capstone is examining
|
||||||
|
// @user_data: user-data passed to cs_option() via @user_data field in
|
||||||
|
// cs_opt_skipdata struct below.
|
||||||
|
// @return: return number of bytes to skip, or 0 to stop disassembling.
|
||||||
|
typedef size_t (*cs_skipdata_cb_t)(size_t offset, void* user_data);
|
||||||
|
|
||||||
|
// User-defined setup for SKIPDATA option
|
||||||
|
typedef struct cs_opt_skipdata {
|
||||||
|
// Capstone considers data to skip as special "instructions".
|
||||||
|
// User can specify the string for this instruction's "mnemonic" here.
|
||||||
|
// By default (if @mnemonic is NULL), Capstone use ".db".
|
||||||
|
const char *mnemonic;
|
||||||
|
// User-defined callback function to be called when Capstone hits data.
|
||||||
|
// If the returned value from this callback is positive (>0), Capstone will skip exactly
|
||||||
|
// that number of bytes & continue. Otherwise, if the callback returns 0, Capstone stops
|
||||||
|
// disassembling and returns immediately from cs_disasm_ex()
|
||||||
|
// NOTE: if this callback pointer is NULL, Capstone skip 1 byte on X86, and 2 bytes on
|
||||||
|
// every other architectures.
|
||||||
|
cs_skipdata_cb_t callback; // default value is NULL
|
||||||
|
// User-defined data to be passed to @callback function pointer.
|
||||||
|
void *user_data;
|
||||||
|
} cs_opt_skipdata;
|
||||||
|
|
||||||
|
|
||||||
#include "arm.h"
|
#include "arm.h"
|
||||||
#include "arm64.h"
|
#include "arm64.h"
|
||||||
|
|
Loading…
Reference in New Issue