1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
/*
Simple routines for working with the value_t data structure.
Copyright (C) 2006,2007,2009 Tavis Ormandy <taviso@sdf.lonestar.org>
Copyright (C) 2009 Eli Dupree <elidupree@charter.net>
Copyright (C) 2009,2010 WANG Lu <coolwanglu@gmail.com>
Copyright (C) 2015 Sebastian Parschauer <s.parschauer@gmx.de>
Copyright (C) 2017 Andrea Stacchiotti <andreastacchiotti(a)gmail.com>
This file is part of libscanmem.
This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VALUE_H
#define VALUE_H
#include <string.h>
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
#include <stdbool.h>
/* some routines for working with value_t structures */
/* match_flags: they MUST be implemented as an `uint16_t`, the `__packed__` ensures so.
* They are reinterpreted as a normal integer when scanning for VLT, which is
* valid for both endians, as the flags are ordered from smaller to bigger.
* NAMING: Primitive, single-bit flags are called `flag_*`, while aggregates,
* defined for convenience, are called `flags_*`*/
typedef enum __attribute__((__packed__)) {
flags_empty = 0,
flag_u8b = 1 << 0, /* could be an unsigned 8-bit variable (e.g. unsigned char) */
flag_s8b = 1 << 1, /* could be a signed 8-bit variable (e.g. signed char) */
flag_u16b = 1 << 2, /* could be an unsigned 16-bit variable (e.g. unsigned short) */
flag_s16b = 1 << 3, /* could be a signed 16-bit variable (e.g. short) */
flag_u32b = 1 << 4, /* could be an unsigned 32-bit variable (e.g. unsigned int) */
flag_s32b = 1 << 5, /* could be a signed 32-bit variable (e.g. int) */
flag_u64b = 1 << 6, /* could be an unsigned 64-bit variable (e.g. unsigned long long) */
flag_s64b = 1 << 7, /* could be a signed 64-bit variable (e.g. long long) */
flag_f32b = 1 << 8, /* could be a 32-bit floating point variable (i.e. float) */
flag_f64b = 1 << 9, /* could be a 64-bit floating point variable (i.e. double) */
flags_i8b = flag_u8b | flag_s8b,
flags_i16b = flag_u16b | flag_s16b,
flags_i32b = flag_u32b | flag_s32b,
flags_i64b = flag_u64b | flag_s64b,
flags_integer = flags_i8b | flags_i16b | flags_i32b | flags_i64b,
flags_float = flag_f32b | flag_f64b,
flags_all = flags_integer | flags_float,
flags_8b = flags_i8b,
flags_16b = flags_i16b,
flags_32b = flags_i32b | flag_f32b,
flags_64b = flags_i64b | flag_f64b,
flags_max = 0xffffU /* ensures we're using an uint16_t */
} match_flags;
/* this struct describes matched values */
typedef struct {
union {
int8_t int8_value;
uint8_t uint8_value;
int16_t int16_value;
uint16_t uint16_value;
int32_t int32_value;
uint32_t uint32_value;
int64_t int64_value;
uint64_t uint64_value;
float float32_value;
double float64_value;
uint8_t bytes[sizeof(int64_t)];
char chars[sizeof(int64_t)];
};
match_flags flags;
} value_t;
/* This union describes 8 bytes retrieved from target memory.
* Pointers to this union are the only ones that are allowed to be unaligned:
* to avoid performance degradation/crashes on arches that don't support unaligned access
* (e.g. ARM) we access unaligned memory only through the attributes of this packed union.
* As described in http://www.alfonsobeato.net/arm/how-to-access-safely-unaligned-data/ ,
* a packed structure forces the compiler to write general access methods to its members
* that don't depend on alignment.
* So NEVER EVER dereference a mem64_t*, but use its accessors to obtain the needed type.
*/
typedef union __attribute__((packed)) {
int8_t int8_value;
uint8_t uint8_value;
int16_t int16_value;
uint16_t uint16_value;
int32_t int32_value;
uint32_t uint32_value;
int64_t int64_value;
uint64_t uint64_value;
float float32_value;
double float64_value;
uint8_t bytes[sizeof(int64_t)];
char chars[sizeof(int64_t)];
} mem64_t;
/* bytearray wildcards: they must be uint8_t. They are ANDed with the incoming
* memory before the comparison, so that '??' wildcards always return true
* It's possible to extend them to fully granular wildcard-ing, if needed */
typedef enum __attribute__ ((__packed__)) {
FIXED = 0xffu,
WILDCARD = 0x00u,
} wildcard_t;
/* this struct describes values provided by users */
typedef struct {
int8_t int8_value;
uint8_t uint8_value;
int16_t int16_value;
uint16_t uint16_value;
int32_t int32_value;
uint32_t uint32_value;
int64_t int64_value;
uint64_t uint64_value;
float float32_value;
double float64_value;
const uint8_t *bytearray_value;
const wildcard_t *wildcard_value;
const char *string_value;
match_flags flags;
} uservalue_t;
/* used when outputting values to user */
/* only works for numbers */
void valtostr(const value_t *val, char *str, size_t n);
/* parse bytearray, it will allocate the arrays itself, then needs to be free'd by `free_uservalue()` */
bool parse_uservalue_bytearray(char *const *argv, unsigned argc, uservalue_t *val);
bool parse_uservalue_number(const char *nptr, uservalue_t * val); /* parse int or float */
bool parse_uservalue_int(const char *nptr, uservalue_t * val);
bool parse_uservalue_float(const char *nptr, uservalue_t * val);
void free_uservalue(uservalue_t *uval);
void valcpy(value_t * dst, const value_t * src);
void uservalue2value(value_t * dst, const uservalue_t * src); /* dst.flags must be set beforehand */
#define get_s8b(val) ((val)->int8_value)
#define get_u8b(val) ((val)->uint8_value)
#define get_s16b(val) ((val)->int16_value)
#define get_u16b(val) ((val)->uint16_value)
#define get_s32b(val) ((val)->int32_value)
#define get_u32b(val) ((val)->uint32_value)
#define get_s64b(val) ((val)->int64_value)
#define get_u64b(val) ((val)->uint64_value)
#define get_f32b(val) ((val)->float32_value)
#define get_f64b(val) ((val)->float64_value)
#define set_s8b(val, v) (((val)->int8_value) = v)
#define set_u8b(val, v) (((val)->uint8_value) = v)
#define set_s16b(val, v) (((val)->int16_value) = v)
#define set_u16b(val, v) (((val)->uint16_value) = v)
#define set_s32b(val, v) (((val)->int32_value) = v)
#define set_u32b(val, v) (((val)->uint32_value) = v)
#define set_s64b(val, v) (((val)->int64_value) = v)
#define set_u64b(val, v) (((val)->uint64_value) = v)
#define set_f32b(val, v) (((val)->float32_value) = v)
#define set_f64b(val, v) (((val)->float64_value) = v)
static inline void zero_value(value_t *val)
{
/* zero components separately -
10 bytes memset() is too slow */
val->int64_value = 0; /* zero the whole union */
val->flags = flags_empty;
}
static inline void zero_uservalue(uservalue_t *val)
{
memset(val, 0, sizeof(*val));
}
#endif /* VALUE_H */
|