#AssaultCube #게임핵 #ESP
Assault Cube 를 이용한 게임핵 개발 연습 시작.
목표는 Single Play 뿐만이 아닌 Multi Play 에서도 사용할 수 있는 ESP 핵을 만드는 것이다.
ESP 핵 중에서도 상대 player 의 체력과 위치가 표시되는 월핵을 제작해보기로 한다.
지난 포스팅에 이어서 같은 Health 주소 값에 브레이크를 걸고 이번에는 피가 빠진 상태에서 힐팩으로 피를 충전해보자.
형광펜 친 부분이 힐팩에 의해 올라간 체력 값을 Health 메모리에 넣는 과정이다.
철저히 확인하자면, eax+4 는 0x028CA278 으로 Health 메모리 주소가 맞다.
그러면 EAX 에 어떻게 저 주소가 들어가게 되었을까? 분명히 Player 에 대한 구조체 혹은 클래스가 존재해서 해당 오브젝트의 베이스 주소를 참조 해서 들어간 값일 텐데...
그래서 우리는 어셈블리를 거꾸로 따라가면서 파악을 해야하는데, 무작정 하기에는 너무 많은 코드가 존재하기에 콜스택을 참조하여 지금 순회중인 서브루틴이 어떤 함수에서 왔는지 확인을 먼저 해보자.
콜스택 맨 위에 지금 순회중인 함수를 call 한 함수가 들어있다. 해당 부분을 따라가본다.
그러면 이런 코드를 볼 수 있는데, 자세히 설명하면
ac_client.exe+2CF69 - E8 B2A3FFFF - call ac_client.exe+27320 // eax 를 반환 하는 함수
ac_client.exe+2CF6E - 50 - push eax
ac_client.exe+2CF6F - 8B C6 - mov eax,esi
ac_client.exe+2CF71 - E8 4ABA0200 - call ac_client.exe+589C0 // 현재 순회 중인 함수, eax 를 인자로 갖고 간다.
ac_client.exe+2CF76 - 83 C4 04 - add esp,04
// Next Assembly...
우리가 순회 중인 함수 그 다음 주소가 콜스택 맨위에 push 되어있는 셈이고, 현재 순회 함수 분석에 앞서서 인자로 들어온 eax 가 무엇인지 한 번 살펴보고 갈 필요가 있다.
그렇게 하기위해서 ac_client.exe+27320
함수를 먼저 탐색해본다. 해당 함수 call 부분에 브레이크를 걸고 다시 힐팩을 먹어보자.
해당 함수가 다행히 길지 않아서 분석량은 많지 않았다. 현재 로컬에서 실행 중인 assaultCube 프로세스의 메모리 베이스에서 0x10F4F4 오프셋을 더한 곳의 값을 eax 로 갖고 와서 특별한 문제가 없다면 return 해주는 함수이다.
※ 보통 베이스 주소는 0x400000 이므로 참조하는 주소는 0x50F4F4 가 될 것이다. 이는 opcode bytes 에도 적혀있다
0x50F4F4 에는 0x28CA180 이 들어가있다.
이건 야매로 판단하는 부분이긴한데 0x028CA274 가 Health 메모리 주소였는데, 주소 대역이 비스무리한 것에서 return 된 주소와 관련이 있다는 것을 어느정도 추측은 하고 들어갈 수 있다.
순회 중인 함수에 들어온 모습이다.
첫 번째 형광펜 부분은 우리가 stack 에 push 한 0x28CA180 를 edi 에 가져오는 모습이다.
두 번째 형광펜 부분은 edi 값에 0xF4 오프셋을 더한 곳의 값을 esi 에 가져오는 모습이다. 이 때, esi 에는 0x028CA274 가 들어오는데 여기서 ㅋㅋ 이 주소가 Health 메모리 보다 4 바이트 작은 부분이라는 것을 알고있어야한다.
세 번째 형광펜 부분은 이 주소 값을 eax 에 전달하는 부분이다.
이런 과정이 끝나면 아래와 같이 아까 브레이크가 걸린 그 부분에 도달한다.
결론적으로 eax 값은 안바뀌었는데, 최초로 0x50F4F4 에서 받아온 EAX 값을 참조로 하여 Health 값을 올리는 것을 확인할 수 있다.
프로세스에 대한 Base 값은 어쨌거나 PE 에 관련된 부분이기에 0x400000 에서 변화는 없을 것이고 0x10F4F4 또한 assault CUBE 자체에 박혀있는 고정 값이므로 변하진 않을 것이다.
이를 근거로 우리는 0x50F4F4 가 Player Object 에 대한 Base Address 라고 판단할 수 있다.
※ 좀 더 명확한 근거가 필요하다면, Health 주소 값에 대해서 pointer scan 을 진행한 후, assault cube 를 재실행해서 rescan 하여도 0x50F4F4 에서 Health 주소 값이 도출된다면 그것을 근거로 하여 0x50F4F4 가 고정적인 Base Address 임을 근거로 제시할 수 있다.
혹시나 0x50F4F4 가 체력에 대한 기능만 할 수도 있으니 테스트로 수류탄 개수도 이 과정을 통해서 진행되는지 살펴보자.
함수 자체는 일단 인자로 쓰일 eax 를 return 하는 함수부터 같은 함수를 사용한다. eax 를 인자로 받는 함수의 경우 예상하기로는 select ... case ...
문 혹은 단순 if 문으로 Player 가 수류탄을 먹는 상황인지, 힐팩을 먹는 상황인지 등등을 구분해놓은 듯하다.
아무튼 위 사진처럼 힐팩 먹는 로직과는 다른 로직으로 와서 eax+64 부분 (현재 수류탄 개수가 담긴 곳) 에 새 수류탄 개수 1 을 넣는 것을 볼 수 있다.
추가로, 마지막에
ac_client.exe+46718 - 8B 48 64 - mov ecx,[eax+64]
ac_client.exe+4671B - 8B 15 B8C24F00 - mov edx,[ac_client.exe+FC2B8] { (3) }
ac_client.exe+46721 - 3B CA - cmp ecx,edx
// Next ...
이 부분을 보면 끝에 3 이 써져있는데, assault cube 에서는 개인 당 수류탄 개수가 최대 3개로 고정되어있다. 그 3 이라는 숫자 또한, assault cube 베이스 주소에 0xFC2B8 오프셋을 더한 곳에 고정적으로 박혀있음을 확인할 수 있다.
이를 이용하여 무한 수류탄도 가능할지도? 모르겠다.
Player 구조체 구성해보기
아무튼 수류탄 개수를 판단하는 것도 같은 Player Object Base Address 를 이용한다는 것을 확인했으니 이제 로컬 Player 에 대한 구조체를 대강 구성해볼 수 있겠다.
지금 까지 알아낸 바는
Player Base 주소(0x50F4F4) 에서 가져온 주소(0x28CA180) 에서 0xF4+0x64 떨어진 곳에 수류탄 개수가 있다는 것.
Player Base 주소(0x50F4F4) 에서 가져온 주소(0x28CA180) 에서 0xF4+0x4 떨어진 곳에 현재 체력 값이 있다는 것.
이다.
이걸 찾는 것은 지난 포스팅의 내용부터 같은 맥락으로 진행되기에 내가 찾은 핵심 값들만 정리해놓고 본 포스팅을 마친다.
struct Player {
int player_x_position;
int player_y_position;
int player_z_position;
// 위 세 개의 값은 memory viewer 로 보면 실시간으로 변한다.
// ESP 월핵 제작시 필수적으로 이용되는 요소!!!
int health;
int ammo;
int current_riffle_bullet;
int guns_remain_bullet[x]; // x 인덱스에 따라 각 총에 대한 교체가능 총알이 저장된다.
// anything...
int grenade;
// more values...
}
'<보안 study> > 리버싱' 카테고리의 다른 글
[게임핵개발연습#4] 게임에선 좌표계산이 어떻게 될까? - 2. screen상의 오브젝트 위치 표시하기 (0) | 2022.01.04 |
---|---|
[게임핵개발연습#3] 게임에선 좌표계산이 어떻게 될까? - 1. viewMatrix 찾기 (0) | 2022.01.03 |
[게임핵개발연습#1] 여러 Local 값과 주소 탐색 (0) | 2021.12.19 |
[IDA] Hex-Rays Code Skip 현상 (1) | 2020.09.12 |
Ghidra-Server 기관에 직접 계정의뢰하기 (0) | 2019.11.27 |