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; }
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; }