- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 395
- Реакции
- 8
Народ, кто сейчас ковыряет ABI под свежие патчи, ловите скомпилированный SDK Reference. Собрал в одну кучу оффсеты, логику декрипта имен и нормальный W2S, чтобы не изобретать велосипед.
Техническое мясо
В этом патче разрабы немного подвинули структуры. Основные моменты:
Актуальные оффсеты
Декрипт GNames (XOR)
В ABI имена зашифрованы, просто так их не вытянуть. Вот рабочий алгоритм для обхода этой темы:
Универсальный WorldToScreen
Математика под UE4 с учетом коррекции аспекта. Работает на 16:9, 21:9 и кастомных разрешениях:
Важное по античиту (ACE)
Метод через ReadProcessMemory сейчас — это гарантированный инста-детект. ACE триггерится на хендлы и RPM очень быстро. Для тестов на твинках пойдет, но если планируете делать что-то серьезное, смотрите в сторону Kernel-драйверов или DMA.
Также учитывайте, что AcknowledgedPawn (0x348) обнуляется в меню и во время загрузки, обязательно ставьте проверку, иначе словите краш.
Кто уже дампил список имен для лут-фильтра, отпишитесь в теме.
Техническое мясо
В этом патче разрабы немного подвинули структуры. Основные моменты:
- CameraCachePrivate уехал с 0x20E0 на 0x20F0. Если у вас игроки и лут рисуются в одной точке или под текстурами — дело в этом.
- FNameID теперь строго 0x20 (раньше был 0x18). Если вместо имен акторов летит мусор — обновляйте.
- Для корректного W2S на ультрашироких мониторах и растянутом разрешении (stretched) добавил Hor+ скейлинг.
Актуальные оффсеты
Код:
// UAGame.exe base + offset
GWorld: 0xA36B8B8
GObjects: 0xA5C1E28
GNames: 0xA88C4C0
FNameXORKey: 0xA8444DC
UObjectFNameID: 0x20
// UWorld
PersistentLevel: 0x30
OwningGameInstance: 0x180
GameState: 0x120
// ULevel
ActorArray: 0x98
ActorCount: 0xA0
// Chain: GameInstance -> LocalPlayers -> PlayerController
LocalPlayers: 0x38
PlayerController: 0x30
// APlayerController
CameraManager: 0x3B0
AcknowledgedPawn: 0x348 // 0 in menu, valid in-game
// APawn
PlayerState: 0x340
RootComponent: 0x170
Mesh: 0x380
// USceneComponent (RootComponent)
RelativeLocation: 0x16C // NOT 0x140 (old dump)
ComponentVelocity: 0x18C
// APlayerCameraManager
CameraCachePrivate: 0x20F0 // NOT 0x20E0 (shifted this patch)
CameraCachePrivate_Rotation: 0x20FC
CameraCachePrivate_FOV: 0x2108
// APlayerState
TeamIndex: 0x598
// ASGCharacter
DeathComponent: 0x1888
CurrentTotalValue: 0x1B5C
WeaponManager: 0x1880
// WeaponManager
CurrentWeapon: 0x1F8
Декрипт GNames (XOR)
В ABI имена зашифрованы, просто так их не вытянуть. Вот рабочий алгоритм для обхода этой темы:
Код:
void DecryptFName(char* buf, int len, uint8_t xor_key) {
uint8_t* p = reinterpret_cast<uint8_t*>(buf);
for (int i = 0; i < len; ++i) {
uint8_t dl = static_cast<uint8_t>(((xor_key >> 1) & 0x08) ^ xor_key);
uint8_t cl = static_cast<uint8_t>(dl ^ ((dl & 0x08) << 1));
uint8_t al = cl;
al &= 0x10;
al ^= 0xEF;
al >>= 1;
p[i] ^= al;
p[i] ^= cl;
}
}
std::string GetNameFromIndex(HANDLE h, uintptr_t base, int key) {
if (key <= 0) return "";
unsigned int chunkIdx = (unsigned int)(key >> 16);
unsigned short nameIdx = (unsigned short)key;
uintptr_t gnames = base + 0xA88C4C0; // GNAMES
uintptr_t poolChunk = Read<uintptr_t>(h, gnames + ((chunkIdx + 2) * 8));
if (!poolChunk) return "";
uintptr_t entry = poolChunk + (2 * nameIdx);
int16_t header = Read<int16_t>(h, entry);
int len = header >> 6;
if (len > 0 && len < 256) {
char buf[256] = {};
ReadProcessMemory(h, (LPCVOID)(entry + 2), buf, len, NULL);
buf[len] = '\0';
uint8_t xor_key = Read<uint8_t>(h, base + 0xA8444DC); // FNAME_XOR_KEY
DecryptFName(buf, len, xor_key);
return std::string(buf, len);
}
return "";
}
}
Универсальный WorldToScreen
Математика под UE4 с учетом коррекции аспекта. Работает на 16:9, 21:9 и кастомных разрешениях:
Код:
struct RotMatrix {
float _11, _12, _13;
float _21, _22, _23;
float _31, _32, _33;
};
RotMatrix BuildRotationMatrix(FRotator rot) {
float p = rot.Pitch * (M_PI / 180.f);
float y = rot.Yaw * (M_PI / 180.f);
float r = rot.Roll * (M_PI / 180.f);
float sp = sinf(p), cp = cosf(p);
float sy = sinf(y), cy = cosf(y);
float sr = sinf(r), cr = cosf(r);
RotMatrix m;
m._11 = cp * cy; m._12 = cp * sy; m._13 = sp;
m._21 = sr*sp*cy - cr*sy; m._22 = sr*sp*sy + cr*cy; m._23 = -sr * cp;
m._31 = -(cr*sp*cy + sr*sy); m._32 = cy*sr - cr*sp*sy; m._33 = cr * cp;
return m;
}
bool WorldToScreen(FMinimalViewInfo cam, FVector world, FVector2D& screen, int w, int h) {
RotMatrix m = BuildRotationMatrix(cam.Rotation);
FVector d = { world.X - cam.Location.X, world.Y - cam.Location.Y, world.Z - cam.Location.Z };
float right = d.X * m._21 + d.Y * m._22 + d.Z * m._23;
float up = d.X * m._31 + d.Y * m._32 + d.Z * m._33;
float forward = d.X * m._11 + d.Y * m._12 + d.Z * m._13;
if (forward < 0.01f) return false;
float fov = cam.FOV;
if (fov <= 0.0f || fov > 170.0f) fov = 90.0f;
float cx = (float)w / 2.0f;
float cy = (float)h / 2.0f;
float aspect = (float)w / (float)h;
float tanHFOV = tanf(fov * 0.5f * (M_PI / 180.0f));
// Hor+ scaling: fixes ultrawide and stretched
screen.X = cx + (right / forward) * (cx / tanHFOV);
screen.Y = cy - (up / forward) * (cx / tanHFOV) * aspect;
return (screen.X >= 0 && screen.X <= w && screen.Y >= 0 && screen.Y <= h);
}
Важное по античиту (ACE)
Метод через ReadProcessMemory сейчас — это гарантированный инста-детект. ACE триггерится на хендлы и RPM очень быстро. Для тестов на твинках пойдет, но если планируете делать что-то серьезное, смотрите в сторону Kernel-драйверов или DMA.
Код:
// After getting hProc and base:
uintptr_t world = Read<uintptr_t>(hProc, base + 0xA36B8B8);
uintptr_t level = Read<uintptr_t>(hProc, world + 0x30);
uintptr_t actors = Read<uintptr_t>(hProc, level + 0x98);
int count = Read<int>(hProc, level + 0xA0);
for (int i = 0; i < count && i < 2000; i++) {
uintptr_t actor = Read<uintptr_t>(hProc, actors + (i * 8));
if (!actor || actor < 0x10000) continue;
int nameID = Read<int>(hProc, actor + 0x20); // UObjectFNameID
std::string name = GetNameFromIndex(hProc, base, nameID);
if (name.empty()) continue;
uintptr_t root = Read<uintptr_t>(hProc, actor + 0x170);
if (root && root > 0x10000) {
FVector pos = Read<FVector>(hProc, root + 0x16C);
printf("[%4d] %-40s pos(%.0f, %.0f, %.0f)\n", i, name.c_str(), pos.X, pos.Y, pos.Z);
} else {
printf("[%4d] %-40s (no root)\n", i, name.c_str());
}
}
Также учитывайте, что AcknowledgedPawn (0x348) обнуляется в меню и во время загрузки, обязательно ставьте проверку, иначе словите краш.
Кто уже дампил список имен для лут-фильтра, отпишитесь в теме.