들어가며
2편에서 ESP를 구현했습니다.
3편에서는 BoneMatrix를 탐색해 정확한 머리 위치를 찾고, 에임봇을 구현하는 과정을 다루며 나아가 글의 마지막에서
YOLO 기반 에임봇과의 차이점 및 총기 반동제거와/에임고정에 대해서도 다룹니다.

⚠️ 주의
: 본 포스팅은 게임 보안 연구 및 렌더링 파이프라인 학습 목적으로 작성되었습니다. 모든 실습은 오프라인 환경(로컬 봇 서버)에서만 진행하였으며, 온라인 서버에서의 악용은 게임사의 이용약관 위반 및 법적 제재 대상이 될 수 있음을 명시합니다.
1. BoneMatrix란?
개요
CS:S의 플레이어 모델은 여러 개의 본(Bone)으로 구성되어 있습니다.
머리, 목, 어깨, 팔꿈치 등 각 관절마다 본이 존재하며, 각 본의 위치와 회전 정보를 담은 것이 BoneMatrix입니다.
플레이어 구조체
└─ [m_dwBoneMatrix: 0x04E4] → 포인터
└─ BoneMatrix 배열
├─ 본 0번: 루트 (3x4 행렬)
├─ 본 1번: 골반
├─ ...
└─ 본 8번: 머리 ← 에임봇 타겟
BoneMatrix 구조
각 본은 3x4행렬 (0x30 = 48바이트) 크기이며, 마지막 열 (4번째 열)이 해당 본의 실제 월드 좌표(XYZ)를 담고 있습니다.
오프셋 내용
0x00 회전 [0][0]
0x04 회전 [0][1]
0x08 회전 [0][2]
0x0C 위치 X ←
0x10 회전 [1][0]
0x14 회전 [1][1]
0x18 회전 [1][2]
0x1C 위치 Y ←
0x20 회전 [2][0]
0x24 회전 [2][1]
0x28 회전 [2][2]
0x2C 위치 Z ←
2. BoneMatrix 오프셋 탐색
LocalPlayer BoneMatrix 접근 제한
탐색을 시작하기 전 중요한 사항이 있습니다. LocalPlayer(자기 자신)의 BoneMatrix는 1인칭 모드에서 계산되지 않습니다.
콘솔에서 thirdperson 명령어를 입력하면 아래와 같은 에러가 출력됩니다.
*** ERROR: Bone access not allowed (entity 1:class C_CSPlayer)
*** ERROR: Bone access not allowed (entity 1:class C_CSPlayer)
따라서 BoneMatrix는 반드시 상대 플레이어 베이스를 기준으로 탐색해야 합니다.
CE에서 봇 베이스 주소 확인:
client.dll + 0x30E3A4 + 0x10 → 봇[1] 베이스 포인터
그 값을 역참조 → 봇 플레이어 베이스 주소
C-CSPlayer 구조체 열기
봇 플레이어 베이스 주소를 입력하면 아래와 같이 C_CSPlayer 구조체를 시각화하여 볼 수 있습니다.

상단에 client.dll의 데이터 섹션을 가리키는 포인터들이 보이며, 오프셋 0x0060에
'models/player/terror.mdl' 모델 경로가 확인됩니다. 이를 통해 현재 열린 구조체가 T팀 봇임을 확인할 수 있습니다.
BoneMatrix 포인터 후보 탐색
구조체를 스크롤하여 0x04AC ~ 0x04E4 범위의 포인터 필드들을 살펴봅니다.

0x04AC, 0x04BC, 0x04C0, 0x04E4 등 여러 포인터 필드들을 확인할 수 있습니다. 각 포인터를 따라가면서 그 안에 행렬 데이터가 있는지 확인해야 합니다.
포인터 따라가기 그리고 BoneMatrix 확인
0x04E4 포인터를 따라가면 아래와 같이 확인할 수 있습니다.

0x04E4 오프셋에 Ptr → 0x24F7FA58 포인터가 존재하며, 해당 포인터가 가리키는 주소를 열면 다음과 같이 보입니다.

해당 메모리 블록을 Matrix(3x4) 타입으로 자동 인식하였습니다. 이것이 BoneMatrix의 시작 주소(0x24F7FA58)임이 확인됩니다.
BoneMatrix 내부 데이터 확인
BoneMatrix 시작 주소를 새 클래스로 열어 내부 데이터를 확인합니다.

0x30 간격으로 3x4 행렬이 반복되는 패턴을 볼 수 있습니다. 각 행렬의 마지막 열(4번째) 값이 해당 본의 월드 좌표입니다.
아래는 최종적으로 확인한 BoneMatrix 포인터 연결 구조입니다.

플레이어 베이스 + 0x04E4 = BoneMatrix 포인터 주소
*(DWORD*)(플레이어 베이스 + 0x04E4) = 0x24F7FA58 (BoneMatrix 시작)
3. 머리 본(Head Bone)인덱스 탐색
탐색 방법
BoneMatrix 시작 주소를 찾았으면 머리에 해당하는 본 인덱스를 찾아야 합니다.
CS:S에서 Z축은 위로 갈수록 값이 커지므로, Z값이 가장 작은 본(가장 높은 위치)이 머리입니다.
각 본의 Z 좌표 계산:
bonePtr + (N * 0x30) + 0x2C
봇 발 Z = -153 (cl_showpos 1로 확인)
머리 Z ≈ 발Z + 68 = -85 근처

콘솔에서 drawcross X Y Z 명령어를 활용하면 특정 좌표에 크로스헤어를 그려 본 위치를 직접 시각적으로 확인할 수 있습니다.
시행착오
여러 본 인덱스를 테스트한 결과:
본 5번 → 가슴 근처
본 8번 → 머리 중앙 (Z값 정확)
본 14번 → 머리 상단 (두피/헬멧 부근)
흥미롭게도 XY 좌표는 14번 본이, Z좌표는 8번 본이 더 정확한 머리 중앙을 가리켰습니다.
이는 CS:S의 머리 본 구조가 일반적인 예상과 다소 다르기 때문인 것으로 보입니다.
Cheat Engine에서 최종 검증
CE에서 포인터 체인으로 머리 XYZ를 추가하여 최종 검증하였습니다.

머리 X = -1039.458862 (bonePtr + 0x2AC)
머리 Y = 1640.8125 (bonePtr + 0x2BC)
머리 Z = -128.316 (bonePtr + 0x1AC)
최종 오프셋 확정



4. 에임봇 구현
각도 계산(Calc Angle)
현재 위치에서 타겟 위치까지의 Pitch/Yaw 각도를 계산하는 함수입니다.

타겟 선택
EntityList에서 가장 거리가 가까운 적을 자동으로 타겟팅 합니다.


ViewAngles 직접 쓰기
계산된 각도를 engine.dll의 ViewAngles 주소에 즉시 기록합니다. 이 방식은 매우 기게적이고 즉각적으로 에임이 이동하는 특성을 가집니다.



5. 최종 오프셋 정리

6. 트러블슈팅
에임봇이 머리 위 허공으로 이동하는 현상
BoneMatrix 오프셋 탐색 과정에서 잘못된 본 인덱스를 사용했을 때 아래 영상과 같이 에임이 플레이어 머리 위 허공으로 고정되는 현상이 발생하였습니다.

원인 분석
처음에는 LocalPlayer를 대상으로 'thirdperson' 모드에서 BoneMatrix를 탐색하였습니다.
그러나 앞서 언급한 것처럼 LocalPlayer는 1인칭 모드에서 BoneMatrix 계산이 이루어지지 않기 때문에 잘못된 메모리 영역의 값을 머리 위치로 오인하게 됩니다.
또한 본 인덱스를 단순히 BONE_HEAD = 14 로 설정했을 때, 실제 머리 중앙이 아닌 헬멧 상단 본을 읽어 에임이 머리보다 높은 위치에 고정되는 문제가 있었습니다.
해결 방법
- LocalPlayer가 아닌 봇플레이어 베이스를 기준으로 탐색
- drawcross 명령어로 각 본 위치를 직접 시각적으로 확인
- XY 좌표와 Z 좌표에 서로 다른 본 인덱스 적용


7. 완성모습


8. 마치며
사실 이 포스팅은 이전 글인 [CS:S] ESP 월핵 / 에임봇 개발기 - 2편: ESP 구현, D3D 후킹 을 포스팅할때 이미 구현을 다 완료 했으나 약 3개월이 지난 지금 이어 작성하게 되었습니다. 글 쓰기가 귀찮아 계속 미루다 보니 이제야 올리게 되었네요
이번 시리즈를 통해 구현한 것들을 정리하면 다음과 같습니다.
- ESP(WallHack) : ViewMatrix를 직접 메로리에서 읽어 WorldToScreen 변환을 구현하고, 벽 너머 적의 위치를 박스와 체력바, 스냅라인으로 시각화
- 에임봇 : BoneMatrix에서 머리 본 위치를 정확히 읽어 우클릭 홀드 시 즉각적으로 머리에 에임을 고정
이전 YOLO 에임봇과의 차이점
이전 포스팅에서 YOLO 기반 에임봇을 구현한 적이 있습니다.
https://imoracle.tistory.com/68
[AI 게임핵의 원리] YOLOv8로 CS:S 에임봇 구현하기
들어가며이전 포스팅에서 D3D9 HOOKING 으로 렌더링 파이프라인을 건드려봤다면, 이번엔 전혀 다른 접근법입니다.게임 내부를 전혀 건드리지 않고 오직 화면 캡처와 AI만으로 에임봇을 구현합니다.
imoracle.tistory.com
두 방식은 구혀 철학 자체가 완전히 다릅니다.
| 항목 | YOLO 기반 | 메모리 기반 (이번 구현) |
| 동작 방식 | 화면을 AI로 인식 | 게임 메모리 직접 읽기 |
| 반응 속도 | 프레임 캡처 > 추론 지연 발생 | 즉각적 (매 프레임 동기화) |
| 정확도 | 픽셀 단위 오차 존재 | 3D 좌표 기반 정밀 조준 |
| 벽 너머 | 화면에 보여야만 인식가능 | 보이지 않아도 좌표 추적 가능 |
| 탐지 위험 | 게임 메모리 무접근 | 메모리 접근 |
| 구현 난이도 | AI 모델 학습 필요 | 오프셋 탐색 필요 |
YOLO 방식은 게임 메모리에 일절 접근하지 않기 때문에 안티치트 탐지를 피하는 데 유리하지만,
화면에 저깅 보여야만 인식이 가능하고 AI 추론 지연으로 인해 반응속도에 한계가 있습니다.
반면 메모리 기반 방식은 벽 너머 적의 3D 좌표를 직접 읽어 즉각적이고 정밀하게 조준할 수 있으며,
ESP처럼 화면에 보이지 않는 정보까지 시각화할 수 있습니다.
다만 메모리에 접근하는 특성상 안티치트에 탐지될 위험이 존재합니다.
반동제거와 탄퍼짐 제거가 중요한 이유
에임봇을 구현하고 나면 자연스럽게 이 두가지의 중요성을 체감하게 됩니다.

총기 무반동 / 반동 제거 (No Recoil)
총을 발사할 때마다 m_vecPunchAngle 값이 증가하면서 화면이 위로 튀어 오릅니다.
에임봇이 머리 좌표를 정확히 계산하더라도, 반동으로 인해 실제 조준 방향이 틀어지면 결국 빗나가게 됩니다.
즉, 에임봇의 정확도를 유지하려면 반동 제거가 필수적 입니다.
에임고정/탄퍼짐 제거 (No Spread)
반동을 제거했다 하더라도 탄퍼짐(Spread)이 존재하면 조준점 중앙이 아닌 무작위 방향으로 총알이 날아갑니다.
특히 연사 시 탄퍼짐이 급격히 커지는 특성상, 에임봇 + 반동 제거가 있어도 탄퍼짐이 있으면
원거리에서의 정확도가 크게 떨어집니다.
완벽한 에임봇을 원한다면 탄퍼짐 제거까지 구현해야 비로소 의미가 있다고 생각 합니다.
애초에 이 프로젝트의 목표가 ESP(월핵)와 에임봇이었던 만큼, 해당 부분은 향후 과제로 남겨두기로 했습니다만 잘 모르겠네요
애당초 이전의 AssualtCube 메모리 게임핵의 포스팅에서 구현한 적이 있기 때문도 있습니다.
이 시리즈를 통해 DirectX 후킹, 메모리 역공학, BoneMatrix 구조 분석까지 다양한 저수준 기술을 직접 손으로 구현해보는 경험을 할 수 있었습니다.
단순히 치트를 만드는 것이 목적이 아니라, 이런 공격 기법이 어떻게 동작하는지 이해함으로써 보안 방어 관점에서의 시야를 넓히는 데 의미가 있다고 생각합니다.
부족한 글이지만 긴 시리즈 읽어주셔서 감사합니다.
이전 글 보러 가기
https://imoracle.tistory.com/82
[CS:S] ESP 월핵 / 에임봇 개발기 - 2편: ESP 구현, D3D 후킹
들어가며지난 1편에서는 치트 엔진을 활용해 플레이어 데이터를 읽어올 수 있는 오프셋과 3D 좌표 변환의 핵심인 ViewMatrix를 메모리에서 직접 찾아내는 과정을 다루었습니다.이번 2편에서는 앞서
imoracle.tistory.com
'Reverse Engineering > GAMEHACK' 카테고리의 다른 글
| [CS:S] ESP 월핵 / 에임봇 개발기 - 2편: ESP 구현, D3D 후킹 (2) | 2026.06.11 |
|---|---|
| [CS:S] ESP 월핵 / 에임봇 개발기 - 1편: 엔티티리스트 탐색과 오프셋 (0) | 2026.06.09 |
| [AntiCheat] 취약 드라이버를 이용한 커널 레벨 안티치트 우회 -1- (3) | 2026.04.08 |
| [게임핵의 역사] 안티치트를 우회해온 기술들의 역사 -왜 게임핵은 사라지지 않는가- (2) | 2026.04.03 |
| [AI 게임핵의 원리] YOLOv8로 CS:S 에임봇 구현하기 (0) | 2026.03.30 |