No need to redact... this stuff has been public knowledge for quite some time. I have yet to see a VMT being checked, and even if they were ret checked, you can easily fake it with a rop gadget. It's just the aggressive checks where they register where functions are direct calls that the ret check requires it from specific calling locations. Stuff like the CGUnit_C::GetPosition is only called from vtable, so it would be a call rax type situation, easy to fake with assembly. As far as transforms:
Code:
 Matrix44 mat;
if (pobj->GetMatrix44(&mat)) {
const auto inv_m = mat.inverse();
const auto rel = inv_m.multiplyVec3(in);
lua_pushvec3(L, rel);
return 3;
}
That's my lua callback code for transforming a world coordinate to the transport relative location (useful for the fights you're on a transport, and the transport moves). Without that, your spells would "slip" off the transport.
Code:
struct Matrix44 {
float m[4][4];
Matrix44() {
m[0][0] = 1.f; m[0][1] = 0.f; m[0][2] = 0.f; m[0][3] = 0.f;
m[1][0] = 0.f; m[1][1] = 1.f; m[1][2] = 0.f; m[1][3] = 0.f;
m[2][0] = 0.f; m[2][1] = 0.f; m[2][2] = 1.f; m[2][3] = 0.f;
m[3][0] = 0.f; m[3][1] = 0.f; m[3][2] = 0.f; m[3][3] = 1.f;
}
Matrix44(float val[4][4]) {
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
m[i][j] = val[i][j];
}
Matrix44 inverse() const {
Matrix44 inv;
// Transpose the 3x3 rotation part (this inverts the rotation)
inv.m[0][0] = m[0][0]; // First column
inv.m[0][1] = m[1][0];
inv.m[0][2] = m[2][0];
inv.m[1][0] = m[0][1]; // Second column
inv.m[1][1] = m[1][1];
inv.m[1][2] = m[2][1];
inv.m[2][0] = m[0][2]; // Third column
inv.m[2][1] = m[1][2];
inv.m[2][2] = m[2][2];
// Invert the translation by applying the inverted rotation to the translation vector
inv.m[3][0] = -(inv.m[0][0] * m[3][0] + inv.m[1][0] * m[3][1] + inv.m[2][0] * m[3][2]);
inv.m[3][1] = -(inv.m[0][1] * m[3][0] + inv.m[1][1] * m[3][1] + inv.m[2][1] * m[3][2]);
inv.m[3][2] = -(inv.m[0][2] * m[3][0] + inv.m[1][2] * m[3][1] + inv.m[2][2] * m[3][2]);
// Set the bottom row (identity matrix row)
inv.m[0][3] = 0.0f;
inv.m[1][3] = 0.0f;
inv.m[2][3] = 0.0f;
inv.m[3][3] = 1.0f;
return inv;
}
Vec3 multiplyVec3(const Vec3& v) const {
Vec3 result;
result.x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0]; // m[3][0] is the x translation
result.y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1]; // m[3][1] is the y translation
result.z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2]; // m[3][2] is the z translation
return result;
}
};
Heck, even the transform matrix shit can be found on this forum from pretty far back if you search properly
VMTs:
CGObject_C::GetPosition - 18 windows, 19 mac
CGObject_C::GetPositionRaw - 19 windows, 20 mac
CGUnit_C::GetFacing - 20 windows, 21 mac
CGUnit_C::GetFacingRaw - 21 windows, 22 mac
Up to you to find the matrix
Which one of the matrix functions that you can use from the mac wod binary is also now behind a ret check
Hint: There is a virtual function that returns the matrix. It's just not as easy to call on MacOS (arm) due to arg2 not being in the correct register if you were to compile the code on your own :P