어렸을 때 즐겨했던 아이작 게임을 분석해보기로 했다.
지뢰찾기 게임보다 순간순간 변하는 값도 많고, 게임 실행마다 메모리 주소가 바뀌는 ASLR 보호기법이 걸려있기 때문에 공부적으로 도움이 될 것 같았다.
원활한 실습을 위해 구버전의 아이작 게임을 타겟으로 선정하고, 치트 엔진을 이용해서 트리거 지점과 메모리 변조를 진행했다.
1. 기본 구성(체력, 폭탄, 돈, 열쇠) 핵 만들기
2. 캐릭터 능력치(공격력, 공격속도, 이동속도 등) 핵 만들기
분석 환경
게임/버전 : Binding OfIsaac Rebirth 1.0
분석 도구 : Cheat Engine 7.4
게임 소개
아이작은 귀여운(?) 게임 캐릭터가 던전 형태의 방을 방문하면서 몬스터/보스를 잡고 최종적으로 게임을 클리어하는 게임이다. 기본 구성으로는 생존 유무를 나타내는 체력, 아이템을 구매할 수 있는 돈, 강력한 무기인 폭탄, 보물상자를 열 수 있는 열쇠가 있다. 또한, 공격력, 이동속도, 공격 속도 등 다양한 캐릭터의 능력치가 존재한다.
분석
게임이 실행될 때마다 메모리 주소가 바뀌는 ASLR이 걸려있기 때문에, 메모리 주소를 직접 변조하게 되면 재실행 시 주소가 달라져서 적용되지 않는다.
따라서, 해당 메모리 값을 참조하는 부분의 어셈블리어를 찾아내거나, 능력치를 담은 메모리 주소 주변에 고정된 값을 통해 주소 지점을 찾는 것이 필요하다. 이 방법은 lua script의 aobscan 함수를 통해 단순하게 메모리에 고정된 헥사 값을 조회하여 주소 값을 받아올 수 있다.
기본 구성(체력, 돈, 폭탄, 열쇠) 분석
캐릭터가 데미지를 입었을 때, 생명력을 나타내는 빨간색 하트가 반 칸씩 줄어 드는 것을 알 수 있었고, 이를 Exact Value로 현재 프로세스에서 체력을 나타내는 변수를 찾을 수 있다. 돈, 폭탄, 열쇠도 마찬가지로 획득했을 때, 또는 소진했을 순간의 변하는 값을 이용해서 각 구성의 변수 메모리 주소를 얻을 수 있다.
원하는 메모리 주소를 찾았다면, 치트 엔진에서 find out what writes to this address
기능으로 해당 메모리를 참조하는 어셈블리어 부분을 찾을 수 있다.
무한 체력(무적)
체력과 같은 경우에는 피격 당했을 시, 체력 값을 1 감소하는 어셈블리어가 존재했다. 이 어셈블리어들은 프로그램을 다시 실행 해도 동일하게 존재하기 때문에, 이 헥사 값을 가지고 aobscan을 하여 해당 부분의 어셈블리어를 패치할 수 있다.
아래 사진은 피격 시 체력을 감소시키는 어셈블리어 부분이다.
eax는 현재 체력의 값을 나타내고, 이를 esp+24에서 데미지의 대한 값을 빼주게 된다. 따라서, sub 명령어를 add로 바꾸면 맞을수록 체력이 늘어나게 된다.
aobscan으로 해당 부분 메모리 주소를 가져와서, 첫 바이트인 2B를 03으로 바꿔주면 sub에서 add로 변경할 수 있다.
Lua Script Code
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
label(life)
registersymbol(life)
aobscan(life_address, 2B 44 24 24 8D 8B 4C 0B 00 00 C7 44 24 20 00 00 00 00)
life_address:
life:
db 03 44 24 24 8D 8B 4C 0B 00 00 C7 44 24 20 00 00 00 00
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
life:
db 2B 44 24 24 8D 8B 4C 0B 00 00 C7 44 24 20 00 00 00 00
unregistersymbol(life)
무한 폭탄
위 사진의 왼쪽을 보면 0x001605E0에서 cmp 명령어를 확인할 수 있다.
이 부분에서 폭탄의 개수를 비교한다. 만약 0보다 크지 않다면(jng) 폭탄을 사용하지 않고, 크다면 폭탄을 사용한다. 따라서, 00의 값을 7f로 설정하여 폭탄을 계속 사용할 수 있도록 변조했다.
Lua Script Code
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
label(life)
registersymbol(life)
aobscan(life_address, 83 3F 00 0F 8E 95 00 00 00 83 BB E4 0C 00 00 00)
life_address:
life:
db 83 3F 7F 0F 8D 95 00 00 00 83 BB E4 0C 00 00 00
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
life:
db 83 3F 00 0F 8E 95 00 00 00 83 BB E4 0C 00 00 00
unregistersymbol(life)
폭탄 개수가 음수로 떨어지지만, 계속 사용할 수 있게 된다.
비싼 동전
앞서 변조와 동일한 방법으로, 동전은 먹었을 경우에 증가해주는 값의 크기를 변조하여 많은 금액이 추가되도록 만들 수 있다.
게임에서는 동전의 범위가 0~99로 설정되어있다. 최대치인지 0x63으로 비교 후, esp를 기준으로 99와 0을 인자를 설정한다. 그리고 99보다 클 경우에는 설정해놓은 esp+10 주소를 eax에 넣게 된다. 이는 99를 덮어쓰는 것이 된다.
또한 아래서 0원일 경우에도 비교를 하게 되는데, 앞서 무한폭탄과 같이 비교 구문을 변조하여 핵을 만들 수 있다. 위 사진의 lea eax, [esp+14]를 lea eax, [esp+10]로 변조하면, 아래서 99 값이 담긴 esp+10주소를 참조하게 된다.
비교 구문을 우회하는 것은 무한 폭탄과 같으므로 자세한 설명은 생략한다.
변수가 0보다 더 클 때 점프하는 코드를 0보다 더 작을 때 점프하게 변조하면, 동전이 0보다 작아질
수 는 없기 때문에 아래 구문을 항상 실행하게 된다.
mov로 값을 대입해주는 식의 구성이 되어 있다. 이를 add로 변경하면 기존 동전 값에서 더 동전이 추가될 것이다.
Lua Script Code
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
label(life)
registersymbol(life)
aobscan(life_address, 7F 04 8D 44 24 14 8B 00 89 83 70 0B 00 00 83 BB 20 0F 00 00 00)
life_address:
life:
db 7C 04 8D 44 24 10 03 00 89 83 70 0B 00 00 83 BB 20 0F 00 00 00
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
life:
db 7F 04 8D 44 24 14 8B 00 89 83 70 0B 00 00 83 BB 20 0F 00 00 00
unregistersymbol(life)
열쇠 복사
동전의 값 어치를 올리는 핵과 동일하게 구현된다. 위 사진 부분이며, 자세한 설명은 생략한다.
Lua Script Code
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
label(life)
registersymbol(life)
aobscan(life_address, 8D 45 08 7C 03 8D 45 FC 83 38 00 7E 0E 8B 00 89 81 64 0B 00 00)
life_address:
life:
db 8D 45 FC 7C 03 8D 45 FC 83 38 00 7C 0E 8B 00 01 81 64 0B 00 00
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
life:
db 8D 45 08 7C 03 8D 45 FC 83 38 00 7E 0E 8B 00 89 81 64 0B 00 00
unregistersymbol(life)
구현 결과
위와 같이 Active 버튼을 통해 메모리 변조를 on/off 할 수 있으며, 변조된 흐름대로 잘 적용되었다.
오늘은 아이작 게임 분석을 통해 기본 구성(체력, 돈, 폭탄, 열쇠)에 대한 핵을 만들어 봤다. 이 4가지(체력, 돈, 열쇠, 폭탄)는 증가하거나 감소하는 지점을 쉽게 찾아낼 수 있었기 때문에 쉽게 구현할 수 있었지만, 캐릭터 능력치에 대한 핵은 이러한 지점을 찾기 쉽지 않을 것 같다.
하지만, 메모리 어딘가에 올라가는 캐릭터 능력치 값 안의 각 구성의 오프셋은 동일할 것이기 때문에 능력치 값을 담는 특정 부분을 찾아내서 오프셋을 통해 캐릭터 능력치 값을 변조를 해볼 것이다.