How to understand Unreal Typecasting
Typecasting or type conversion is the concept of converting one data type into another, for example turning the string "1" into the numeric value 1.
Different operators are used for different data types. Some operator types only support certain variable types. There are both explicit statements to convert, and implicit conversions that occur automatically when an assignment, operator or function call requires it.
Programs and Tools
While not required to understand this article, see the following articles for descriptions and links to the tools used to exploit the information provided.
Rather than repeating well covered material, the reader is recommended to first read the Typecasting article to gain the necessary background on the issue. From there we proceed to cover particular instances with the Unreal Game Engine that have given our 'code divers' problems.
The remainder of this article consists primarily of 'lessons learned'.
- Until recently it has been difficult to find an instance where declaring an integer constant using 24 or 2C made an noticeable difference.
- Some people have been the habit of using 2C tokens as visually they seem easier to pick out than the 24 tokens.
- The original construction was:
- if (eItem == 3)
- 07 88 00 9A 38 3A 00 77 40 00 00 38 3A 24 03 16
- The == operator turns out to only be valid for integers, not for bytes, which is why eItem has a '38 3A' byte-to-int token pair in front of it.
- Interestingly, the 3 value '24 03' also had a '38 3A' byte-to-int token pair.
- Changing the hex to:
- if (eItem == 3)
- 07 88 00 9A 38 3A 00 77 40 00 00 38 3A 2C 03 16
- the game would crash-to-desktop when the code was executed. Reverting it back to '24 03' solved the issue.
- This is, at it's core, an operator typecasting issue.
- Apparently there is no "==" operator for comparing byte/enum values.
- To compare a class to 'none', (e.g. m_kUnit == none) you have to use the 0x72 token (or 0x77 for "!=").
- For integer comparison it's 0x9A
- For float comparisons it's 0xB4
- There's no integer version of ABS -- it only works on floats.
- The "*=" operator has a version for integer on left side (0x9F), and for float on left side (I think 0xB6), but all versions require a float on the right side. Using an integer on right side causes CTD.
As for the conversion tokens (most of which weren't defined in the list included with the modding package), here's what we have so far:
- Always a 38 ## byte pair:
- EX_PrimitiveCast = 0x38
- Second bytes known:
- EX_RotatorToVector = 0x39
- EX_ByteToInt = 0x3A;
- EX_IntToByte = 0x3D
- EX_IntToFloat = 0x3F
- EX_FloatToInt = 0x44
- EX_StringToInt = 0x4A (string to int)
- string(int) = 0x53 (int to string)
- string(object) = 0x56 (object to string)
- float(int) = 0x3F (int to float)
Referred to by this article:
- Difference between 0x24 and 0x2C tokens
That refer to this article: