Skip to content

Commit 69d1be3

Browse files
committed
computation of Jcc & JMP target
1 parent c8afc8f commit 69d1be3

File tree

3 files changed

+122
-27
lines changed

3 files changed

+122
-27
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ Here below how you can use the struct. More infos and the other structs can be f
107107
| `modrm` | `union` | Union of four fields: `value`, `rm`, `reg` and `mod` (see [below](#modrm-union)). |
108108
| `disp` | `uint64_t` | Displacement field |
109109
| `imm` | `uint64_t` | Immediate value (a number) |
110+
| `label` | `uint32_t` | Address of Jcc/JMP, if present |
110111
| `_vex` | `struct vex_info` | Available only if [`_ENABLED_VEX_INFO`](#enabling--disabling-features) is defined. Described [below](#vex_info-struct). |
111112
| `instr` | `uint8_t[15]` | Available only if [`_ENABLE_RAW_BYTES`](#enabling--disabling-features) is defined. |
112113
| `sib` | `union` | Union of four fields: `value`, `base`, `index` and `scaled` (see [below](#sib-union)). |
@@ -118,6 +119,7 @@ Here below how you can use the struct. More infos and the other structs can be f
118119
| `prefix_cnt` | `int8_t` | Count how many prefixes are available |
119120
| `set_prefix` | `uint16_t` | A field against which is possible to check if a determined prefix (belonging to `prefixes` enum) is present. |
120121
| `set_field` | `uint16_t` | A field against which is possible to check if a determined feature (belonging to `instruction_feature` enum) is available (e.g. FPU, SIB, DISP,...) |
122+
| `jcc_type` | `uint8_t` | The type of jump: Jcc or JMP with 1 or 2-bytes (refer to jmp_type enum)
121123
122124
___
123125

src/mca.c

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <stdio.h>
12
#include "mca.h"
23

34
static size_t *imm_table[4] = {0, imm_byte_2b,imm_byte_3b_38,imm_byte_3b_3A };
@@ -14,22 +15,22 @@ static inline void mca_vex_decode(struct instruction *instr, enum supported_arch
1415
instr->set_prefix |= VEX;
1516

1617
if(instr->vex[0] == 0xC5) {
17-
#ifdef _ENABLE_VEX_INFO
18-
instr->_vex.type = instr->vex[0];
19-
instr->_vex.val5 = instr->vex[1];
20-
#endif
18+
#ifdef _ENABLE_VEX_INFO
19+
instr->_vex.type = instr->vex[0];
20+
instr->_vex.val5 = instr->vex[1];
21+
#endif
2122

22-
mca_decode_modrm(instr, arch, data, modrm_2b, imm_byte_2b);
23+
mca_decode_modrm(instr, arch, data, modrm_2b, imm_byte_2b, NULL);
2324
}
2425
else if(instr->vex[0] == 0xC4) {
2526

26-
#ifdef _ENABLE_VEX_INFO
27-
instr->_vex.type = instr->vex[0];
28-
memcpy(&instr->_vex.val4, &instr->vex[1],2);
29-
#endif
27+
#ifdef _ENABLE_VEX_INFO
28+
instr->_vex.type = instr->vex[0];
29+
memcpy(&instr->_vex.val4, &instr->vex[1],2);
30+
#endif
3031

3132
int8_t index = instr->vex[1] & 0x3;
32-
mca_decode_modrm(instr, arch, data, modrm_table[index], imm_table[index]);
33+
mca_decode_modrm(instr, arch, data, modrm_table[index], imm_table[index], NULL);
3334
}
3435
// TODO XOP, 0x8F
3536

@@ -105,7 +106,7 @@ static inline int mca_imm_size(struct instruction *instr, size_t val, enum suppo
105106
}
106107
}
107108

108-
static void mca_decode_modrm(struct instruction *instr, enum supported_architecture arch, const char *start_data, const size_t *modrm_table, const size_t *imm_table) {
109+
static void mca_decode_modrm(struct instruction *instr, enum supported_architecture arch, const char *start_data, const size_t *modrm_table, const size_t *imm_table, const size_t *jcc_table) {
109110
size_t val;
110111
if((val = modrm_table[instr->op])) {
111112
instr->set_field |= MODRM;
@@ -147,6 +148,32 @@ static void mca_decode_modrm(struct instruction *instr, enum supported_architect
147148
memcpy(&instr->imm, (start_data + instr->length), instr->imm_len);
148149
instr->length += instr->imm_len;
149150
}
151+
152+
uint16_t value = 0;
153+
if(jcc_table != NULL && (value = jcc_table[instr->op])) {
154+
switch(value) {
155+
case j1:
156+
instr->jcc_type = JMP_SHORT;
157+
break;
158+
case j2:
159+
instr->jcc_type = JMP_FAR;
160+
break;
161+
case jc1:
162+
instr->jcc_type = JCC_SHORT;
163+
break;
164+
case jc2:
165+
instr->jcc_type = JCC_FAR;
166+
default:
167+
break; // avoid compiler warnings
168+
}
169+
170+
// 1-byte
171+
if(value & 0x10)
172+
instr->label = (uint32_t)start_data + ((int8_t)instr->imm) + instr->length;
173+
// 4-byte
174+
else
175+
instr->label = (uint32_t)start_data + ((int32_t)instr->imm) + instr->length;
176+
}
150177
}
151178

152179
static int mca_decode_2b(struct instruction *instr, enum supported_architecture arch, const char *data_src)
@@ -164,17 +191,17 @@ static int mca_decode_2b(struct instruction *instr, enum supported_architecture
164191
instr->length++;
165192

166193
if(curr == 0x3A)
167-
mca_decode_modrm(instr, arch, data_src, modreg_3b_3A, imm_byte_3b_3A);
194+
mca_decode_modrm(instr, arch, data_src, modreg_3b_3A, imm_byte_3b_3A, NULL);
168195
else
169-
mca_decode_modrm(instr, arch, data_src, modreg_3b_38, imm_byte_3b_38);
196+
mca_decode_modrm(instr, arch, data_src, modreg_3b_38, imm_byte_3b_38, NULL);
170197

171198
return instr->length;
172199
}
173200

174201
instr->op = curr;
175202
instr->length++;
176203

177-
mca_decode_modrm(instr, arch, data_src, modrm_2b, imm_byte_2b);
204+
mca_decode_modrm(instr, arch, data_src, modrm_2b, imm_byte_2b, op2b_labels);
178205

179206
return instr->length;
180207
}
@@ -190,33 +217,33 @@ int mca_decode(struct instruction *instr, enum supported_architecture arch, char
190217
switch(curr) {
191218
case 0x26:
192219
instr->set_prefix |= ES;
193-
break;
220+
break;
194221
case 0x2E:
195222
instr->set_prefix |= CS;
196-
break;
223+
break;
197224
case 0x36:
198225
instr->set_prefix |= SS;
199-
break;
226+
break;
200227
case 0x3E:
201228
instr->set_prefix |= DS;
202-
break;
229+
break;
203230
case 0x48:
204231
case 0x49:
205232
if(arch == X64)
206233
instr->set_prefix |= OP64;
207-
break;
234+
break;
208235
case 0x64:
209236
instr->set_prefix |= FS;
210-
break;
237+
break;
211238
case 0x65:
212239
instr->set_prefix |= GS;
213-
break;
240+
break;
214241
case 0x66:
215242
instr->set_prefix |= OS;
216-
break;
243+
break;
217244
case 0x67:
218245
instr->set_prefix |= AS;
219-
break;
246+
break;
220247
}
221248

222249
instr->set_field |= PREFIX;
@@ -235,9 +262,9 @@ int mca_decode(struct instruction *instr, enum supported_architecture arch, char
235262
else if(curr == 0x0F)
236263
{
237264
mca_decode_2b(instr, arch, start_data);
238-
#ifdef _ENABLE_RAW_BYTES
265+
#ifdef _ENABLE_RAW_BYTES
239266
memcpy(instr->instr, start_data, instr->length);
240-
#endif
267+
#endif
241268
return instr->length;
242269
}
243270

@@ -251,7 +278,7 @@ int mca_decode(struct instruction *instr, enum supported_architecture arch, char
251278
{
252279
instr->length++;
253280
instr->op = curr;
254-
mca_decode_modrm(instr, arch, start_data, modrm_1b, imm_byte_1b);
281+
mca_decode_modrm(instr, arch, start_data, modrm_1b, imm_byte_1b, op1b_labels);
255282
}
256283

257284
#ifdef _ENABLE_RAW_BYTES

src/mca.h

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,42 @@ static size_t imm_byte_1b[256] = {
9696
/* F0 */ 0, 0, 0, 0, 0, 0, gr3b, gr3z, 0, 0, 0, 0, 0, 0, 0, 0
9797
};
9898

99+
/*
100+
* first byte:
101+
* - 1: 1-byte
102+
* - 2: 4-byte
103+
*
104+
* second byte (LSB):
105+
* - 1: Jcc
106+
* - 2: JMP
107+
*
108+
*/
109+
#define j1 0x12
110+
#define j2 0x22
111+
#define jc1 0x11
112+
#define jc2 0x21
113+
114+
// check if the OP is Jcc or JMP
115+
static size_t op1b_labels[256] = {
116+
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
117+
/* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118+
/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119+
/* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120+
/* 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121+
/* 40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122+
/* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123+
/* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124+
/* 70 */ jc1, jc1, jc1, jc1, jc1, jc1, jc1, jc1, jc1, jc1, jc1, jc1, jc1, jc1, jc1, jc1,
125+
/* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126+
/* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127+
/* A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128+
/* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129+
/* C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130+
/* D0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131+
/* E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, j2, 0, j1, 0, 0, 0, 0,
132+
/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
133+
};
134+
99135
//
100136
// 2-byte OP look-up table
101137

@@ -156,6 +192,27 @@ static size_t imm_byte_2b[256] = {
156192
/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
157193
};
158194

195+
// check if the OP is Jcc or JMP
196+
static size_t op2b_labels[256] = {
197+
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
198+
/* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
199+
/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
200+
/* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
201+
/* 30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
202+
/* 40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
203+
/* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
204+
/* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
205+
/* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
206+
/* 80 */ jc2, jc2, jc2, jc2, jc2, jc2, jc2, jc2, jc2, jc2, jc2, jc2, jc2, jc2, jc2, jc2,
207+
/* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
208+
/* A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
209+
/* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210+
/* C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
211+
/* D0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
212+
/* E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
213+
/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
214+
};
215+
159216
//
160217
// 3-byte OP look-up table
161218

@@ -250,6 +307,13 @@ static size_t imm_byte_3b_3A[256] = {
250307
/* F0 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
251308
};
252309

310+
enum jmp_type {
311+
JCC_SHORT = 1, // 1-byte JCC
312+
JCC_FAR = 2, // 2-byte JCC, 4bytes imm
313+
JMP_SHORT = 4, // 1-byte JMP
314+
JMP_FAR = 8, // 4-byte JMP
315+
};
316+
253317
enum prefixes {
254318
ES = 1, // 0x26
255319
CS = 2, // 0x2E
@@ -336,6 +400,7 @@ struct vex_info {
336400
struct instruction {
337401
uint64_t disp;
338402
uint64_t imm;
403+
uint32_t label;
339404

340405
#ifdef _ENABLE_VEX_INFO
341406
struct vex_info _vex;
@@ -390,6 +455,7 @@ struct instruction {
390455

391456
uint16_t set_prefix; // bit mask
392457
uint16_t set_field;
458+
uint8_t jcc_type;
393459

394460
int8_t vex_cnt;
395461
int8_t prefix_cnt;
@@ -400,7 +466,7 @@ struct instruction {
400466
// Functions
401467
//
402468
int mca_decode(struct instruction *instr, enum supported_architecture arch, char *data_src, int offset);
403-
static void mca_decode_modrm(struct instruction *instr, enum supported_architecture arch, const char *data_src, const size_t *modrm_table, const size_t *imm_table);
469+
static void mca_decode_modrm(struct instruction *instr, enum supported_architecture arch, const char *data_src, const size_t *modrm_table, const size_t *imm_table, const size_t *jcc_table);
404470
static inline bool mca_check_sib(uint8_t mod, uint8_t rm);
405471
static inline int mca_displacement_size(uint8_t mod, uint8_t rm);
406472
static inline int mca_imm_size(struct instruction *instr, size_t val, enum supported_architecture arch);

0 commit comments

Comments
 (0)