Ejemplo n.º 1
0
 private static void CopyOpcode(ldasm_data *pLdasmData, void *pCode, byte[] opcodes, uint offset)
 {
     for (byte i = 0; i < pLdasmData->opcd_size; i++)
     {
         opcodes[offset + pLdasmData->opcd_offset + i] = ((byte *)pCode)[pLdasmData->opcd_offset + i];
     }
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Disassemble one instruction
        /// </summary>
        /// <param name="code">pointer to the code for disassemble</param>
        /// <param name="ld">pointer to structure ldasm_data</param>
        /// <param name="is64">set this flag for 64-bit code, and clear for 32-bit</param>
        /// <returns>length of instruction</returns>
        public static uint ldasm(void *code, ldasm_data *ld, bool is64)
        {
            byte *p = (byte *)code;
            byte  s, op, f;
            byte  rexw, pr_66, pr_67;

            s = rexw = pr_66 = pr_67 = 0;

            /* dummy check */
            if (code == null || ld == null)
            {
                return(0);
            }

            /* init output data */
            *ld = new ldasm_data();

            /* phase 1: parse prefixies */
            while ((cflags(*p) & OP_PREFIX) != 0)
            {
                if (*p == 0x66)
                {
                    pr_66 = 1;
                }
                if (*p == 0x67)
                {
                    pr_67 = 1;
                }
                p++; s++;
                ld->flags |= F_PREFIX;
                if (s == 15)
                {
                    ld->flags |= F_INVALID;
                    return(s);
                }
            }

            /* parse REX prefix */
            if (is64 && *p >> 4 == 4)
            {
                ld->rex    = *p;
                rexw       = (byte)((ld->rex >> 3) & 1);
                ld->flags |= F_REX;
                p++; s++;
            }

            /* can be only one REX prefix */
            if (is64 && *p >> 4 == 4)
            {
                ld->flags |= F_INVALID;
                s++;
                return(s);
            }

            /* phase 2: parse opcode */
            ld->opcd_offset = (byte)(p - (byte *)code);
            ld->opcd_size   = 1;
            op = *p++; s++;

            /* is 2 byte opcode? */
            if (op == 0x0F)
            {
                op = *p++; s++;
                ld->opcd_size++;
                f = cflags_ex(op);
                if ((f & OP_INVALID) != 0)
                {
                    ld->flags |= F_INVALID;
                    return(s);
                }
                /* for SSE instructions */
                if ((f & OP_EXTENDED) != 0)
                {
                    op = *p++; s++;
                    ld->opcd_size++;
                }
            }
            else
            {
                f = cflags(op);
                /* pr_66 = pr_67 for opcodes A0-A3 */
                if (op >= 0xA0 && op <= 0xA3)
                {
                    pr_66 = pr_67;
                }
            }

            /* phase 3: parse ModR/M, SIB and DISP */
            if ((f & OP_MODRM) != 0)
            {
                byte mod = (byte)(*p >> 6);
                byte ro  = (byte)((*p & 0x38) >> 3);
                byte rm  = (byte)(*p & 7);

                ld->modrm  = *p++; s++;
                ld->flags |= F_MODRM;

                /* in F6,F7 opcodes immediate data present if R/O == 0 */
                if (op == 0xF6 && (ro == 0 || ro == 1))
                {
                    f |= OP_DATA_I8;
                }
                if (op == 0xF7 && (ro == 0 || ro == 1))
                {
                    f |= OP_DATA_I16_I32_I64;
                }

                /* is SIB byte exist? */
                if (mod != 3 && rm == 4 && !(!is64 && pr_67 != 0))
                {
                    ld->sib    = *p++; s++;
                    ld->flags |= F_SIB;

                    /* if base == 5 and mod == 0 */
                    if ((ld->sib & 7) == 5 && mod == 0)
                    {
                        ld->disp_size = 4;
                    }
                }

                switch (mod)
                {
                case 0:
                    if (is64)
                    {
                        if (rm == 5)
                        {
                            ld->disp_size = 4;
                            if (is64)
                            {
                                ld->flags |= F_RELATIVE;
                            }
                        }
                    }
                    else if (pr_67 != 0)
                    {
                        if (rm == 6)
                        {
                            ld->disp_size = 2;
                        }
                    }
                    else
                    {
                        if (rm == 5)
                        {
                            ld->disp_size = 4;
                        }
                    }
                    break;

                case 1:
                    ld->disp_size = 1;
                    break;

                case 2:
                    if (is64)
                    {
                        ld->disp_size = 4;
                    }
                    else if (pr_67 != 0)
                    {
                        ld->disp_size = 2;
                    }
                    else
                    {
                        ld->disp_size = 4;
                    }
                    break;
                }

                if (ld->disp_size != 0)
                {
                    ld->disp_offset = (byte)(p - (byte *)code);
                    p         += ld->disp_size;
                    s         += ld->disp_size;
                    ld->flags |= F_DISP;
                }
            }

            /* phase 4: parse immediate data */
            if (rexw != 0 && (f & OP_DATA_I16_I32_I64) != 0)
            {
                ld->imm_size = 8;
            }
            else if ((f & OP_DATA_I16_I32) != 0 || (f & OP_DATA_I16_I32_I64) != 0)
            {
                ld->imm_size = (byte)(4 - (pr_66 << 1));
            }

            /* if exist, add OP_DATA_I16 and OP_DATA_I8 size */
            ld->imm_size += (byte)(f & 3);

            if (ld->imm_size != 0)
            {
                s += ld->imm_size;
                ld->imm_offset = (byte)(p - (byte *)code);
                ld->flags     |= F_IMM;
                if ((f & OP_RELATIVE) != 0)
                {
                    ld->flags |= F_RELATIVE;
                }
            }

            /* instruction is too long */
            if (s > 15)
            {
                ld->flags |= F_INVALID;
            }

            return(s);
        }