mirror of
https://github.com/MalwareTech/EDR-Preloader
synced 2026-06-08 11:40:03 +00:00
416 lines
10 KiB
C++
416 lines
10 KiB
C++
/*
|
|
* Hacker Disassembler Engine 64 C
|
|
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
|
* All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#if defined(_M_X64) || defined(__x86_64__)
|
|
|
|
#include <string.h>
|
|
#include "hde64.h"
|
|
|
|
#define C_NONE 0x00
|
|
#define C_MODRM 0x01
|
|
#define C_IMM8 0x02
|
|
#define C_IMM16 0x04
|
|
#define C_IMM_P66 0x10
|
|
#define C_REL8 0x20
|
|
#define C_REL32 0x40
|
|
#define C_GROUP 0x80
|
|
#define C_ERROR 0xff
|
|
|
|
#define PRE_ANY 0x00
|
|
#define PRE_NONE 0x01
|
|
#define PRE_F2 0x02
|
|
#define PRE_F3 0x04
|
|
#define PRE_66 0x08
|
|
#define PRE_67 0x10
|
|
#define PRE_LOCK 0x20
|
|
#define PRE_SEG 0x40
|
|
#define PRE_ALL 0xff
|
|
|
|
#define DELTA_OPCODES 0x4a
|
|
#define DELTA_FPU_REG 0xfd
|
|
#define DELTA_FPU_MODRM 0x104
|
|
#define DELTA_PREFIXES 0x13c
|
|
#define DELTA_OP_LOCK_OK 0x1ae
|
|
#define DELTA_OP2_LOCK_OK 0x1c6
|
|
#define DELTA_OP_ONLY_MEM 0x1d8
|
|
#define DELTA_OP2_ONLY_MEM 0x1e7
|
|
|
|
unsigned char hde64_table[] = {
|
|
0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
|
|
0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
|
|
0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
|
|
0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
|
|
0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
|
|
0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
|
|
0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
|
|
0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
|
|
0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
|
|
0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
|
|
0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
|
|
0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
|
|
0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
|
|
0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
|
|
0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
|
|
0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
|
|
0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
|
|
0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
|
|
0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
|
|
0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
|
|
0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
|
|
0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
|
0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
|
|
0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
|
|
0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
|
|
0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
|
|
0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
|
|
0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
|
|
0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
|
|
0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
|
|
0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
|
|
0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
|
|
0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
|
|
0x00,0xf0,0x02,0x00
|
|
};
|
|
|
|
unsigned int hde64_disasm(const void *code, hde64s *hs)
|
|
{
|
|
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
|
|
uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
|
|
uint8_t op64 = 0;
|
|
|
|
memset(hs, 0, sizeof(hde64s));
|
|
|
|
for (x = 16; x; x--)
|
|
switch (c = *p++) {
|
|
case 0xf3:
|
|
hs->p_rep = c;
|
|
pref |= PRE_F3;
|
|
break;
|
|
case 0xf2:
|
|
hs->p_rep = c;
|
|
pref |= PRE_F2;
|
|
break;
|
|
case 0xf0:
|
|
hs->p_lock = c;
|
|
pref |= PRE_LOCK;
|
|
break;
|
|
case 0x26: case 0x2e: case 0x36:
|
|
case 0x3e: case 0x64: case 0x65:
|
|
hs->p_seg = c;
|
|
pref |= PRE_SEG;
|
|
break;
|
|
case 0x66:
|
|
hs->p_66 = c;
|
|
pref |= PRE_66;
|
|
break;
|
|
case 0x67:
|
|
hs->p_67 = c;
|
|
pref |= PRE_67;
|
|
break;
|
|
default:
|
|
goto pref_done;
|
|
}
|
|
pref_done:
|
|
|
|
hs->flags = (uint32_t)pref << 23;
|
|
|
|
if (!pref)
|
|
pref |= PRE_NONE;
|
|
|
|
if ((c & 0xf0) == 0x40) {
|
|
hs->flags |= F_PREFIX_REX;
|
|
if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
|
|
op64++;
|
|
hs->rex_r = (c & 7) >> 2;
|
|
hs->rex_x = (c & 3) >> 1;
|
|
hs->rex_b = c & 1;
|
|
if (((c = *p++) & 0xf0) == 0x40) {
|
|
opcode = c;
|
|
goto error_opcode;
|
|
}
|
|
}
|
|
|
|
if ((hs->opcode = c) == 0x0f) {
|
|
hs->opcode2 = c = *p++;
|
|
ht += DELTA_OPCODES;
|
|
}
|
|
else if (c >= 0xa0 && c <= 0xa3) {
|
|
op64++;
|
|
if (pref & PRE_67)
|
|
pref |= PRE_66;
|
|
else
|
|
pref &= ~PRE_66;
|
|
}
|
|
|
|
opcode = c;
|
|
cflags = ht[ht[opcode / 4] + (opcode % 4)];
|
|
|
|
if (cflags == C_ERROR) {
|
|
error_opcode:
|
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
cflags = 0;
|
|
if ((opcode & -3) == 0x24)
|
|
cflags++;
|
|
}
|
|
|
|
x = 0;
|
|
if (cflags & C_GROUP) {
|
|
uint16_t t;
|
|
t = *(uint16_t *)(ht + (cflags & 0x7f));
|
|
cflags = (uint8_t)t;
|
|
x = (uint8_t)(t >> 8);
|
|
}
|
|
|
|
if (hs->opcode2) {
|
|
ht = hde64_table + DELTA_PREFIXES;
|
|
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
|
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
}
|
|
|
|
if (cflags & C_MODRM) {
|
|
hs->flags |= F_MODRM;
|
|
hs->modrm = c = *p++;
|
|
hs->modrm_mod = m_mod = c >> 6;
|
|
hs->modrm_rm = m_rm = c & 7;
|
|
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
|
|
|
|
if (x && ((x << m_reg) & 0x80))
|
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
|
|
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
|
|
uint8_t t = opcode - 0xd9;
|
|
if (m_mod == 3) {
|
|
ht = hde64_table + DELTA_FPU_MODRM + t * 8;
|
|
t = ht[m_reg] << m_rm;
|
|
}
|
|
else {
|
|
ht = hde64_table + DELTA_FPU_REG;
|
|
t = ht[t] << m_reg;
|
|
}
|
|
if (t & 0x80)
|
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
}
|
|
|
|
if (pref & PRE_LOCK) {
|
|
if (m_mod == 3) {
|
|
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
}
|
|
else {
|
|
uint8_t *table_end, op = opcode;
|
|
if (hs->opcode2) {
|
|
ht = hde64_table + DELTA_OP2_LOCK_OK;
|
|
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
|
|
}
|
|
else {
|
|
ht = hde64_table + DELTA_OP_LOCK_OK;
|
|
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
|
|
op &= -2;
|
|
}
|
|
for (; ht != table_end; ht++)
|
|
if (*ht++ == op) {
|
|
if (!((*ht << m_reg) & 0x80))
|
|
goto no_lock_error;
|
|
else
|
|
break;
|
|
}
|
|
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
no_lock_error:
|
|
;
|
|
}
|
|
}
|
|
|
|
if (hs->opcode2) {
|
|
switch (opcode) {
|
|
case 0x20: case 0x22:
|
|
m_mod = 3;
|
|
if (m_reg > 4 || m_reg == 1)
|
|
goto error_operand;
|
|
else
|
|
goto no_error_operand;
|
|
case 0x21: case 0x23:
|
|
m_mod = 3;
|
|
if (m_reg == 4 || m_reg == 5)
|
|
goto error_operand;
|
|
else
|
|
goto no_error_operand;
|
|
}
|
|
}
|
|
else {
|
|
switch (opcode) {
|
|
case 0x8c:
|
|
if (m_reg > 5)
|
|
goto error_operand;
|
|
else
|
|
goto no_error_operand;
|
|
case 0x8e:
|
|
if (m_reg == 1 || m_reg > 5)
|
|
goto error_operand;
|
|
else
|
|
goto no_error_operand;
|
|
}
|
|
}
|
|
|
|
if (m_mod == 3) {
|
|
uint8_t *table_end;
|
|
if (hs->opcode2) {
|
|
ht = hde64_table + DELTA_OP2_ONLY_MEM;
|
|
table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
|
|
}
|
|
else {
|
|
ht = hde64_table + DELTA_OP_ONLY_MEM;
|
|
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
|
|
}
|
|
for (; ht != table_end; ht += 2)
|
|
if (*ht++ == opcode) {
|
|
if ((*ht++ & pref) && !((*ht << m_reg) & 0x80))
|
|
goto error_operand;
|
|
else
|
|
break;
|
|
}
|
|
goto no_error_operand;
|
|
}
|
|
else if (hs->opcode2) {
|
|
switch (opcode) {
|
|
case 0x50: case 0xd7: case 0xf7:
|
|
if (pref & (PRE_NONE | PRE_66))
|
|
goto error_operand;
|
|
break;
|
|
case 0xd6:
|
|
if (pref & (PRE_F2 | PRE_F3))
|
|
goto error_operand;
|
|
break;
|
|
case 0xc5:
|
|
goto error_operand;
|
|
}
|
|
goto no_error_operand;
|
|
}
|
|
else
|
|
goto no_error_operand;
|
|
|
|
error_operand:
|
|
hs->flags |= F_ERROR | F_ERROR_OPERAND;
|
|
no_error_operand:
|
|
|
|
c = *p++;
|
|
if (m_reg <= 1) {
|
|
if (opcode == 0xf6)
|
|
cflags |= C_IMM8;
|
|
else if (opcode == 0xf7)
|
|
cflags |= C_IMM_P66;
|
|
}
|
|
|
|
switch (m_mod) {
|
|
case 0:
|
|
if (pref & PRE_67) {
|
|
if (m_rm == 6)
|
|
disp_size = 2;
|
|
}
|
|
else
|
|
if (m_rm == 5)
|
|
disp_size = 4;
|
|
break;
|
|
case 1:
|
|
disp_size = 1;
|
|
break;
|
|
case 2:
|
|
disp_size = 2;
|
|
if (!(pref & PRE_67))
|
|
disp_size <<= 1;
|
|
break;
|
|
}
|
|
|
|
if (m_mod != 3 && m_rm == 4) {
|
|
hs->flags |= F_SIB;
|
|
p++;
|
|
hs->sib = c;
|
|
hs->sib_scale = c >> 6;
|
|
hs->sib_index = (c & 0x3f) >> 3;
|
|
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
|
|
disp_size = 4;
|
|
}
|
|
|
|
p--;
|
|
switch (disp_size) {
|
|
case 1:
|
|
hs->flags |= F_DISP8;
|
|
hs->disp.disp8 = *p;
|
|
break;
|
|
case 2:
|
|
hs->flags |= F_DISP16;
|
|
hs->disp.disp16 = *(uint16_t *)p;
|
|
break;
|
|
case 4:
|
|
hs->flags |= F_DISP32;
|
|
hs->disp.disp32 = *(uint32_t *)p;
|
|
break;
|
|
}
|
|
p += disp_size;
|
|
}
|
|
else if (pref & PRE_LOCK)
|
|
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
|
|
if (cflags & C_IMM_P66) {
|
|
if (cflags & C_REL32) {
|
|
if (pref & PRE_66) {
|
|
hs->flags |= F_IMM16 | F_RELATIVE;
|
|
hs->imm.imm16 = *(uint16_t *)p;
|
|
p += 2;
|
|
goto disasm_done;
|
|
}
|
|
goto rel32_ok;
|
|
}
|
|
if (op64) {
|
|
hs->flags |= F_IMM64;
|
|
hs->imm.imm64 = *(uint64_t *)p;
|
|
p += 8;
|
|
}
|
|
else if (!(pref & PRE_66)) {
|
|
hs->flags |= F_IMM32;
|
|
hs->imm.imm32 = *(uint32_t *)p;
|
|
p += 4;
|
|
}
|
|
else
|
|
goto imm16_ok;
|
|
}
|
|
|
|
|
|
if (cflags & C_IMM16) {
|
|
imm16_ok:
|
|
hs->flags |= F_IMM16;
|
|
hs->imm.imm16 = *(uint16_t *)p;
|
|
p += 2;
|
|
}
|
|
if (cflags & C_IMM8) {
|
|
hs->flags |= F_IMM8;
|
|
hs->imm.imm8 = *p++;
|
|
}
|
|
|
|
if (cflags & C_REL32) {
|
|
rel32_ok:
|
|
hs->flags |= F_IMM32 | F_RELATIVE;
|
|
hs->imm.imm32 = *(uint32_t *)p;
|
|
p += 4;
|
|
}
|
|
else if (cflags & C_REL8) {
|
|
hs->flags |= F_IMM8 | F_RELATIVE;
|
|
hs->imm.imm8 = *p++;
|
|
}
|
|
|
|
disasm_done:
|
|
|
|
if ((hs->len = (uint8_t)(p - (uint8_t *)code)) > 15) {
|
|
hs->flags |= F_ERROR | F_ERROR_LENGTH;
|
|
hs->len = 15;
|
|
}
|
|
|
|
return (unsigned int)hs->len;
|
|
}
|
|
|
|
#endif // defined(_M_X64) || defined(__x86_64__)
|