1. Home
  2. 보안 강좌/CheatEngine
  3. [Cheat Engine] 치트엔진 튜토리얼 #7 풀이

[Cheat Engine] 치트엔진 튜토리얼 #7 풀이

글을 읽기 전 필요한 지식

어셈블리 명령어 (x86 / x64 intel / amd 명령어)

컴퓨팅 구조

 

Step 7: 코드 인젝션: (PW = 013370)
코드 인젝션은 대상 프로세스에 코드 조각을 삽입하고, 코드 실행을 자체 작성한 코드를 통해 재지정하는 기술입니다.

이번 튜토리얼에서는 클릭할 때마다 체력이 1씩 감소하는 체력 값과 버튼이 있습니다.
당신의 임무는 코드 인젝션을 사용하여 버튼을 클릭할 때마다 체력을 2씩 증가시키는 것입니다.

먼저 주소를 찾은 다음, 그것에 쓰는 것을 찾으세요. (원문 : find what writes to it)
그런 다음, 감소시키는 코드가 있는 주소로 이동하여 디스어셈블러에서 해당 주소를 찾고, 자동 어셈블러 창 (Ctrl + A)을 엽니다.
그곳에서 템플릿을 클릭한 다음, 코드 인젝션을 클릭하고 체력을 감소시키는 주소를 제공합니다 (이미 올바르게 입력되어 있지 않은 경우).
이것은 코드 인젝션에 대한 기본 자동 어셈블러 인젝션 프레임워크를 생성하며, 당신이 사용할 수 있습니다.

alloc에 주목해보세요. 이것은 코드 케이브를 위한 메모리 블록을 할당할 것입니다. 이전 Windows 2000 시스템에서는 메모리의 코드 케이브를 찾아야 했습니다. 그러나 다행스럽게도 Windows 2000 이후에는 그것이 과거의 일이 되었으며 새 CPU의 NX 비트 및 XP SP2로 인해 사용하려고하면 오류가 발생할 것입니다.

또한 newmem: 및 originalcode: 및 "여기에 코드를 넣으세요"라는 텍스트를 볼 수 있습니다.
당신이 상상할 수 있듯이, 여기에 체력을 2 증가시키는 코드를 작성합니다. 이 경우 유용한 어셈블러 명령어는 "ADD 명령어"입니다.

다음은 몇 가지 예시입니다.
"ADD [00901234], 9"는 00901234 주소의 값을 9로 증가시킵니다.
"ADD [ESP + 4], 9"는 ESP + 4가 가리키는 주소의 값을 9로 증가시킵니다.
이 경우, 체력을 감소시키는 원래 코드와 동일한 것을 괄호 사이에 사용해야 합니다.

주의사항:
체력을 감소시키는 코드를 원래 코드 섹션에서 삭제하는 것이 좋습니다. 그렇지 않으면 체력을 3으로 증가시켜야 하기 때문에 혼동될 수 있습니다. 하지만 이는 당신과 당신의 프로그래밍에 달려 있습니다.

주의사항 2:
일부 게임에서 원래 코드는 여러 명령으로 구성될 수 있으며, 때로는 다른 위치에서 코드가 점프해 복잡한 동작을 일으킬 수 있습니다. 이런 경우에는 일반적으로 해당 명령어 근처를 살펴보고 점프를 수정하거나 다른 주소를 선택하여 코드 인젝션을 수행해야 합니다. 그러나 인젝트 코드 내부에서 변경할 주소를 찾을 수 있다면 가능합니다.

 

이번문제는 저번 #5단계와 동일하게 어셈블리 명령어를 수정해야 하는 문제입니다.

그러나 이번엔 좀 특이하게 "코드 인젝션" 이라는 기법을 사용해야 하는데요.

 

치트엔진에선 쉽게 코드 인젝션을 하는것을 지원하기도 하고, 코드 인젝션이라는 기법 자체가 리버싱을 배울 때 꽤 뒤에서 배우는 내용이므로 저번처럼 #5단계 정도에서 설명했던 이론 정도만 알고 계시면 문제 자체는 어렵지 않게 해결 하실 수 있을겁니다.

 

일단은 여기까지 왔으므로 기초적인 컴퓨팅 지식과 인텔 x86 어셈블리어를 어느정도 안다고 가정하고 출발하도록 하겠습니다.

 

Solution

 

항상 하던대로 값 주소부터 찾습니다.

Health를 찾아내야 하므로 100, Exact Value, 4Bytes 로 검색합니다.

 

값 변경후 99를 다시 검색하면 Health 의 메모리 값을 찾을 수 있습니다.

 

일단은 아래에 등록해두고! 지금 문제에서 읽었다 싶이 저희가 이번에 해야할 일은 저 Hit me 버튼을 눌렀을때 체력이 1 감소하는게 아니라 2씩 증가하게 만들어야 합니다.

 

아마 게임에서 이런 조작을 했다면 플레이어가 총에맞거나 적에 닿아도 체력이 닿는게 아니라 체력이 오히려 회복되는 치트를 만들 수 있었겠죠 ㅎㅎ.

 

일단은 이번에도 앞에서 배운 진리

1. 모든 프로그램(프로세스)는 RAM위에서 실행된다

2. RAM 에 데이터를 읽고 쓰는 주체는 CPU다

=> CPU 명령어를 통해  RAM에 데이터를 읽고 쓸 수 있음.

 

2가지를 가지고 시작합니다.

자 Hit me를 눌렀을때 어떤 CPU 명령어가 실행되서 Health를 1감소 시키고 화면에 출력되고 있을 것이며, 

그 명령어가 어떤 명령어인지, 어디서 실행되고 있는지 우선 찾아내야 합니다.

 

그래야 CPU가 체력을 1 감소 시키는 명령어를 조작해서, 2로 증가시키는 명령어로 바꿀 수 있겠죠.

 

아시다 싶이 what writes.. 기능을 사용하면 해당 메모리 공간에 어떤 CPU 명령어가 개입하여 수정되고 있는지 알 수 있습니다. 체력엔 어떤 CPU 명령어가 실행되어서 -1이 되고 있을까요. 

Find out what writes to this address 기능을 통해 찾아봅시다.

 

앞에서 배웠다 싶이 what writes 는 어떤 명령어가 이 메모리 값을 직접 바꾸는지 찾는거고, what access 는 어떤 포인터 변수가 이 값을 바꾸는지 찾는거였습니다.

일단 튜토리얼에선 what writes 로 찾으라는걸로 봐서 이 변수는 포인터를 이용해서 바꾸는건 아닌가 봅니다.

 

디버거 Attach 하는 메세지랑, Hit me 누르는 과정은 따로 보여드리지 않고 생략하고

일단은 Hit me 를 누르는 순간에 실행되는 CPU 명령은 다음과 같습니다.

 

10002DB57 - 83 AE E0070000 01 - sub dword ptr [rsi+000007E0],01
;rsi : 00000000015A7860
;rsi + 000007E0 = 15A8040

저 RAM 주소 위치에 값을 바꾸는데 개입된 CPU 명령어는 딱 1줄인데요.

sub는 무엇을 뺄 때 사용하는 어셈블리어입니다. (subtract)

 

[**sub dword ptr [rsi+000007E0],01**] 의 의미는 rsi+000007E0 가 가리키는 주소로 RAM에서 찾아가서, 그 값에서 1만큼 빼고 저장해라! 라는 뜻이 됩니다.

 

현재 rsi 레지스터에는 15A7860 라는 어떤 주소가 담겨있고 여기에 +000007E0 을 해서 주소를 계산하고 있습니다.

일단은 결론부터 말씀드리자면 rsi + 000007E0 = 15A8040  이며, 당연하지만 15A8040은 health 가 저장된 곳의 메모리 주소입니다.

 

위 sub 명령어를 한줄로 요약하면 health 가 저장된 곳의 메모리 주소로 가서, 그 값을 참조해 1만큼 빼라! 가 되겠네요.

저기 위에 dword ptr이 궁금하신 분들이 있을건데, 지금 메모리 주소를 이용해 값을 참조하고 있으므로 ptr은 pointer를 의미하는거고, dword는 4바이트를 의미합니다. (double word, 참고로 word는 2바이트)
가리키는 공간이 4바이트 크기라는것을 알려주는 것이지요. C언어의 int * ptr 과 같은 의미입니다. [C언어에서 포인터의 자료형은 가리키는 공간의 크기를 의미.]

 

어쨌던 우리가 해야될 일은 체력이 깎이는데 sub라는 명령어가 관여를 하는걸로 알았으니깐

저 명령어를 잘 지지고 볶아서 수정해주면 될 것 입니다.

 

사실 저번처럼 명령어를 직접 바꿔서 풀어도 되는데 어셈블리어에는 sub랑 반대되게 어떤 공간의 주소를 증가시키는 add라는 명령어가 있습니다. (이와 비슷하게 inc - dec 라는 명령어 쌍도있음)

 

Single Line Assembler(어셈블리 코드 한줄을 원하는걸로 바꾸는 기능) 를 이용해서 inc 명령어로 고쳐도 되지만, 일단은 본 글에서 코드 인젝션을 사용해서 문제를 풀라고 했으므로 따라가도록 하겠습니다.

 

Show disassembler 버튼을 눌러서 디스어셈블러 창을 엽니다.

 

다시 머리 아픈 창이 나왔네요! 지금 하이라이팅 된 부분이 실제로 Health를 1뺄 때 실행되는 CPU 명령어 코드의 위치입니다. 위 아래는 튜토리얼 프로그램이 실행해야 할, 또는 이미 실행했던 수 많은 명령어들의 모음들이구요.

 

이 상태에서 Tools - Auto Assemble을 누릅니다.

이를 이용하면 쉽게 코드 인젝션을 수행할 수 있습니다. (치트엔진에서 제공하는 간편기능)

 

하얀 창이 나오면서 코드를 작성하라고 하는데

Template - Code Injection 을 이용하여 코드 인젝션시 사용하는

템플릿 코드를 불러옵시다.

 

주소를 입력하라고 나오는데 아까 sub 명령어를 선택해둔 주소이므로 OK를 누릅니다.

 

그러면 이렇게 코드 템플릿이 자동으로 완성되며 original code에 본래 실행되는 sub 명령어가 들어가게 됩니다. 우리는 이 소스코드를 바꾸어서, 코드 인젝션을 수행하면 됩니다.

 

코드 인젝션이란 상대방 프로세스에 독립 실행 코드를 삽입한 후 실행하는 기법이다. [https://maple19out.tistory.com/43]
코드 인젝션에 대해선 쓸 내용이 많으므로 본 글에선 자세히 설명하지 않습니다. 나중에 리버싱 관련 글을 작성하게 되면 다루어 보도록 하겠습니다.

 

지금 우리의 목적은 sub 명령어 대신에 체력값을 증가시키는 코드를 삽입(Code Injection) 하는게 목적입니다.

아까도 말씀드렸듯이 무언가 값을 증가시키는 명령어는 add이며, [rsi+000007E0] 는 체력 값이 저장된 주소의 값, 즉 체력값을 의미하므로, 저 체력값에 2씩 더하는 코드를 삽입해주면 됩니다.

 

add dword ptr [rsi+000007E0],02

originalcode 부분에 우리가 삽입할 코드를 이렇게 변경시켜 줍니다.

이러면 아까 sub 부분에 실행되어야 할 명령어가 이렇게 우리가 작성한 add 명령어로 대체 되어서 실행되게 됩니다.

치트엔진이 코드인젝션에 대한 복잡한 부분들은 알아서 자동으로 처리해주므로 우리는 이렇게 스크립트만 잘 작성해주면 됩니다.

 

Execute 버튼을 눌러서 코드 인젝션을 실행하고, 코드 인젝션을 수행할꺼냐고 묻는 창이뜨면 Yes, 코드 인젝션이 성공했다는 창이 떠서 거기로 이동할꺼냐고 물어보면 No를 누릅니다.

 

이제 튜토리얼 프로그램으로 돌아와서 Hit me 를 누르면 감소햇던 체력이 감동적이게도 이렇게 2씩 증가하는걸 볼 수 있습니다. 저희가 임의로 코드를 삽입해서 원래 sub로 빠지던 체력 명령어를 add로 삽입해서 변조했기 때문입니다.

 

이제 Hit me를 계속 눌러도 sub 명령어는 더 이상 실행되지 않으며 저희가 삽입한 add 명령어만  계속 실행되는걸 볼 수 있습니다. (왼쪽에 증가하는 Count라는 숫자가 명령어의 실행 횟수입니다.)

 

코드 인젝션 후 어셈블러 창을 보면 우리가 아까 삽입한 코드가 위치하고 jmp로 다시 원래 흐름으로 돌리는걸 볼 수 있습니다. FFFF0000 이라는 빈 곳에다가 삽입할 코드를 작성하고 jmp로 원래 위치로 돌리나보네요. 

매우 재미있습니다.

 

아까 원래 실행되던 위치로 돌아와서 또 살펴보니 실행되던 sub 명령어는 jmp FFFF0000 으로 대체되었고, 빈 공간(바이트)은 NOP으로 채워놨네요. 코드인젝션의 원리가 빈 공간으로 점프시켜서 거기에 우리가 작성한 명령어를 실행시킨뒤, 다시 jmp 시켜서 원래 흐름으로 돌리는 방법인가봅니다.

 

예전에 어셈블리어를 하나도 모를땐 문제 풀이는 가능해도 이해가 하나도 안됐는데 이제 좀 알고 보니깐 재미있는거 같습니다. 하하하. 

 

여러분도 어셈블리어 공부해보세요

 

 

출처

https://www.youtube.com/watch?v=pku7jCxm03U 

 

SNS 공유하기
네이버밴드
카카오톡
페이스북
X(트위터)

최근글
인기글
이모티콘창 닫기
울음
안녕
감사
당황
피폐