bool AnalyzeOperand(XEDPARSE* Parse, const char* Value, InstOperand* Operand)
{
    REG registerVal     = RegFromString(Value);
    ULONGLONG immVal    = 0;

    if(registerVal != REG_INVALID)
    {
        // Register
        Operand->Type       = OPERAND_REG;
        Operand->Segment    = REG_INVALID;
        Operand->Size       = RegGetSize(registerVal);
        Operand->XedEOSZ    = OpsizeToEosz(Operand->Size);
        Operand->Reg.Reg    = registerVal;
        Operand->Reg.XedReg = RegToXed(registerVal);
    }
    else if(strchr(Value, '[') && strchr(Value, ']'))
    {
        // Memory
        Operand->Type       = OPERAND_MEM;
        Operand->Segment    = REG_INVALID;
        Operand->Size       = SIZE_UNSET;
        Operand->XedEOSZ    = EOSZ_64_32(Parse->x64);

        return HandleMemoryOperand(Parse, Value, Operand);
    }
    else if(strchr(Value, ':'))
    {
        // Segment selector operand
        Operand->Type       = OPERAND_SEGSEL;
        Operand->Segment    = REG_INVALID;
        Operand->Size       = SIZE_DWORD;
        Operand->XedEOSZ    = EOSZ_64_32(Parse->x64);

        return HandleSegSelectorOperand(Parse, Value, Operand);
    }
    else if(valfromstring(Value, &immVal) || (Parse->cbUnknown && Parse->cbUnknown(Value, &immVal)))
    {
        // Immediate
        Operand->Type       = OPERAND_IMM;
        Operand->Segment    = REG_INVALID;
        Operand->Size       = OpsizeFromValue(immVal);
        Operand->XedEOSZ    = EOSZ_64_32(Parse->x64);
        Operand->Imm.Signed = (Value[0] == '-');
        Operand->Imm.imm    = immVal;
    }
    else
    {
        // Unknown
        Operand->Type = OPERAND_INVALID;

        sprintf(Parse->error, "Unknown operand identifier '%s'", Value);
        return false;
    }

    return true;
}
Exemple #2
0
bool HandleMemoryOperand(XEDPARSE* Parse, const char* Value, InstOperand* Operand)
{
    // Copy the prefix into a buffer
    char prefix[64];

    strcpy(prefix, Value);
    *strchr(prefix, '[') = '\0';

    // Copy the calculation into a buffer (strrchr is intentional)
    char calc[64];

    if(strrchr(Value, '[') > strrchr(Value, ']'))
    {
        // Someone tried using a closing bracket before the opening
        strcpy(Parse->error, "Invalid memory bracket open/close pair");
        return false;
    }

    strcpy(calc, strrchr(Value, '[') + 1);
    *strchr(calc, ']') = '\0';

    // Gather any information & check the prefix validity
    if(strlen(prefix) > 0)
    {
        // Prefix must be lowercase
        _strlwr(prefix);

        // Remove 'ptr' if it exists and remove colons
        StrDel(prefix, "ptr", '\0');
        StrDel(prefix, ":", '\0');

        // Check if the segment can be used
        size_t len = strlen(prefix);

        if(len >= 2)
        {
            // Move backwards in order to get the segment (SIZE-SEG[CALC])
            char* segPtr = (prefix + (len - 2));

            // See if the segment is actually valid
            REG segment = RegFromString(segPtr);

            if(segment != REG_INVALID)
            {
                // Set the new segment
                Operand->Segment = segment;

                // End the string here
                *segPtr = '\0';
            }
        }

        // Determine the prefix size
        Operand->Size = OpsizeFromString(prefix);

        // If the size is UNSET and there's still chars left in the string,
        // it is an invalid identifier
        if(Operand->Size == SIZE_UNSET && strlen(prefix) > 0)
        {
            sprintf(Parse->error, "Unknown identifier in '%s'", Value);
            return false;
        }

        // Update the effective operand size for Xed
        Operand->XedEOSZ = OpsizeToEosz(Operand->Size);
    }

    // Begin determining the calculation
    // [Base + (Index * Scale) + Displacement] -- IN ANY ORDER
    if(strlen(calc) <= 0)
    {
        strcpy(Parse->error, "Invalid memory calculation");
        return false;
    }

    char temp[32];
    char* ptr    = calc;
    char* base   = temp;
    bool mulFlag = false;

    for(;; ptr++)
    {
        *base = '\0';

        switch(*ptr)
        {
        case '\0':
        case '+':
        case '-':
            if(mulFlag)
                SetMemoryIndexOrScale(Parse, temp, Operand);
            else
                SetMemoryDisplacementOrBase(Parse, temp, Operand);

            base    = temp;
            mulFlag = false;

            if(*ptr == '-')
                *base++ = '-';
            break;

        case '*':
            SetMemoryIndexOrScale(Parse, temp, Operand);

            base    = temp;
            mulFlag = true;
            break;

        default:
            *base++ = *ptr;
            break;
        }

        if(*ptr == '\0')
            break;
    }

    // Fix up the operand segment
    if(Operand->Segment == REG_INVALID)
    {
        if((Operand->Mem.BaseVal == REG_ESP || Operand->Mem.BaseVal == REG_EBP) && !Parse->x64)
        {
            // If the segment isn't set and the base is ESP or EBP,
            // auto-set the segment to SS
            Operand->Segment = REG_SS;
        }
        else
        {
            // Default to DS
            // 64-bit also doesn't have true segments except for FS/GS/DS
            Operand->Segment = REG_DS;
        }
    }

    if(Operand->Mem.Disp)
    {
        // If the base isn't set, the displacement must be at least 32 bits
        if(!Operand->Mem.Base)
            Operand->Mem.DispWidth = max(Operand->Mem.DispWidth, SIZE_DWORD);

        // Use RIP-relative addressing per default when on x64 and when the displacement is set
        // and when the segment is SEG_DS
        if(Parse->x64 && Operand->Segment == REG_DS)
        {
            if(!Operand->Mem.Base && !Operand->Mem.Index && !Operand->Mem.Scale)
            {
                // If a 32-bit address was given, don't apply RIP-relative addressing
                if(true || Operand->Mem.DispWidth != SIZE_DWORD) //removed this because rip-relative instructions are smaller
                {
                    LONGLONG newDisp = TranslateRelativeCip(Parse, Operand->Mem.DispVal, true);
                    ULONGLONG masked = newDisp & 0xFFFFFFFF00000000;

                    // Check if the mask fits into a 32-bit variable (taking sign-extension into account)
                    if(masked == 0 || masked == 0xFFFFFFFF00000000)
                    {
                        Operand->Mem.DispVal     = newDisp;
                        Operand->Mem.DispWidth   = SIZE_DWORD;
                        Operand->Mem.Base        = true;
                        Operand->Mem.BaseVal     = REG_RIP;
                        Operand->Mem.ImplicitRip = true;
                    }
                    else
                        Operand->Mem.DispWidth = SIZE_QWORD;
                }
            }
        }
    }
    else if(!Operand->Mem.Base && Operand->Mem.Index && Operand->Mem.Scale)
    {
        // Handle when only an index register and scale are set
        // Ex: MOV EAX, [ECX * 8]
        Operand->Mem.Disp      = true;
        Operand->Mem.DispVal   = 0;
        Operand->Mem.DispWidth = SIZE_DWORD;
    }

    return true;
}