What i did
1. 리버싱에 대해 알아보았다.
2. 실행 파일들의 어셈블리 코드를 보며 분석하는 실습을 진행했다.
3.오픈 소스 메모리 스캐너 및 디버거 도구인 cheat engine을 활용하여 과제를 했다.
What I learn
리버싱이란 완성된 프로그램을 분석해 소스 구조를 파악하는 과정으로, 내부 구조나 동작 방식, 데이터 흐름 등을 역으로 추적하는 과정이다. 리버싱은 각종 프로그램의 보안성을 평가하거나 악성코드를 분석하는 등 다양하게 활용된다.
어셈블리어는 사람이 이해할 수 있는 형태의 기계어에 가까운 언어이다. 0과 1로 구성된 기계어를 사람이 좀 더 읽기 쉽게 바꾼 언어로, 기계어보다는 이해하기 낫지만 여전히 복잡한 Low-Level Language이다.
C/C++ 프로그램을 기계어로 변환하는 전체 흐름을 살펴보자면 processing-compilation-assemble-linking 이다.
먼저 개발자가 소스코드를 작성하면 컴파일 과정이 시작된다.
1. processing: 소스 코드에 있는 지시문을 처리해, 실제 컴파일이 가능하게 만드는 준비 단계이다. 결과로는 텍스트로 완성된 소스인 .i 또는 .ii 파일을 생성한다.
2. Compilation: 이전 과정에서 전처리된 코드를 어셈블리어 코드로 번역해 사람이 이해할 수 있는 중간 언어로 바꿔서 기계어로 옮기기 직전까지 다듬는 단계이다. 결과로는 어셈블리어 텍스트인 .s파일이 생성된다.
3. Assembling: 어셈블리어 코드를 컴퓨터가 바로 읽을 수 있는 기계어(이진 코드)로 번역하는 단계다. 기계어로 된 목적 파일 (.o, .obj) 이 생성된다.
4. Linking: 각각 따로 만들어진 목적 파일들과 라이브러리들을 한데 묶어서 하나의 실행 파일로 만드는 단계이다. 결과로는 실행 가능한 파일인 .exe 등이 생성된다.
여기서 어셈블리어는 2단계에서 출력이 되어서 3단계의 입력값이 된다.
대표적인 실행 파일 형식으로는 ELF와 PE가 있다. ELF( Executable and Linkable Format )의 사용 운영 체제는 Linux, Unix 계열이고, 확장자는 .out, .so 등이 있다. 주요 용도로는 실행 파일, 공유 라이브러리, 커널 모듈 등으로 사용된다. 주로 리눅스에서만 사용된다. PE( Portable Executable )의 사용 운영 체제는 Windows이며, 확장자로는 .exe, .dll, .sys 등이 있다. 주요 용도로는 실행 파일, 동적 라이브러리, 드라이버 등으로 사용된다. 다양한 Windows 버전에서 호환된다. 따라서 ELF는 리눅스, PE는 윈도우용 실행 파일 형식이며, 서로는 형식이 다르기 때문에 호환되지는 않는다.
둘의 확장자인 .exe와 .dll 에 대해서 알아보자면, .exe(Executable) 는 독립적으로 실행되고 자체적으로 실행 가능한 애플리케이션이다. main 함수를 포함한 프로그램은 exe로 컴파일 된다. 하나의 독립적인 프로그램으로, 일반적으로 하나의 애플리케이션에는 하나의 exe 파일만 포함된다. 예시로는 주로 사용자의 앱, 게임, 유틸리티 등이 있다. .dll(Dynamic Link Library) 은 독립적으로 실행되지 않고 다른 애플리케이션을 지원하는 파일이다. main 함수가 없는 프로그램이 dll로 컴파일된다. 코드나 기능을 공유하는 하이브러리로, 한 애플리케이션에서의 수량은 고정되지 않으며, 여러 개가 포함될 수 있다. 예시로는 시스템 함수, 그래픽 처리 등으로 사용된다.
리버싱 툴에는 ida, ghiidra, x64dbg, ollydbg 등 다양한 도구들이 있다.
이 중 ida 에 대해 자세히 알아보자면 ida는 디스어셈블러 및 디버거로 MS-DOS 콘솔 애플리케이션으로 시작되어 현재는 윈도우, 리눅스, 맥OS를 모두 지원한다. ida는 라이선스 형대로 제공되며 이는 유료이고 상당히 비싸다.. 하는 역할은 바이너리 파일을 읽고, 내부 기계어 코드를 어셈블리 코드로 변환하는 일을 하고, 함수, 변수, 문자열을 자동 식별해주며, 제어 흐름 그래프를 제공해 시각화가 가능하다. 현재는 보안 분석과 악성코드 분석에 널리 사용되고 있다.
Weekly Challenge
오픈 소스 메모리 스캐너 및 디버거 도구인 Cheat Engine을 다운로드 해 준 다음, 튜토리얼을 실행한다.
1단계: 아래 첫번째 사진과 같은 탭이 나온다. 참고로 사진의 오른쪽 밑에 있는 패스워드는 각 단계별로 튜토리얼을 진행하다가 나중에 진행했던 튜토리얼에 맞추어 계속 실행할 수 있도록 각 단계마다 패스워드를 지정해, 그 칸에 단계별 패스워드를 입력하면 그 단계로 바로 넘어가게 하는 역할을 한다. 1단계의 내용을 보자면, Open Process 아이콘을 클릭해 이 튜토리얼의 프로세스를 열라고 한다. 실행하면 아래의 두 번째 사진처럼 위에 튜토리얼과 관련된 파일의 이름이 보인다.
2단계: 내용을 읽어보면, 이 창 하단에 있는 Health라는 텍스트 옆의 숫자는 Hit me를 클릭할 때 마다 줄어든다고 한다. 그래서 다음 단계로 넘어가기 위해서는 이 값을 찾아 1000으로 변경해야한다고 적혀있다. 아래의 health를 한 번 누르니 값이 98이 되어서 value값에 98을 넣어봤더니 한 개의 주소가 나왔다. 처음 값이 100이고, 현재 값이 98이라는 변수가 health 값이 있는 곳 인 것 같았다. 확실하게 하기 위해 한 번 더 눌러보았더니 숫자가 95가 되었고 아까 보았던 주소의 현재 값도 95가 되었다는 것을 확인할 수 있었다. 그러므로 이 주소를 더블 클릭해서 value 값을 1000으로 바꿔주면 health 값이 1000으로 늘어나게 된다.
3단계: 알 수 없는 0부터 500 사이의 값이 있다. 그리고 hit me를 누를 때 마다 이 숫자가 감소한다. 이 숫자를 찾아서 값을 5000으로 만들어라는 문제 이다. 2단계는 값을 알고 있었기 때문에 정확한 값 검색을 할 수 있었지만, 이제는 값이 0에서 500 사이라는 것과 감소하는 정도만 알 수 있다. 감소하는 정도를 알아보기 위해 먼저 hit me 버튼을 누르면 -7만큼 감소했다고 뜬다. 그래서 scan type을 drcreased value by ... 로 바꾸고 감소한 수인 7을 입력하면 0부터 500사이의 값이 하나밖에 나오지 않아서 이 주소로 확정한 후 더블클릭해서 value 값을 5000으로 바꾸어주면 된다.
4단계: 이전 단계들 까지는 정수를 다루었는데 이제는 정수를 저장한다고 한다. 아래에 있는 health 값과 ammo값은 각각 float, double 에 저장되어 있는 수라고 한다. health를 클릭하면 숫자가 줄어들고, ammo를 클릭하면 0.5만큼 줄어든다고 한다. 이 두 값을 모두 5000 이상의 수로 만드는게 목표이다. 먼저, value type을 float로 바꾸어 준 다음, 현재 health 값인 100을 입력하면 정확히 100인 값이 하나 나온다. 확실하게 하기 위해 health를 한 번 누르니 아까 보았던 주소의 현재 value가 같은 수만큼 줄어든 것을 확인할 수 있었다. 그래서 이 값을 더블클릭해주고 value 값을 5000으로 바꾸어준다. 그 다음, ammo 값의 주소를 찾기 위해 scan type를 double로 바꾸고 100을 입력해주면 하나의 주소밖에 나오지 않기 때문에 이 주소로 확정한 후, value 값을 5000으로 바꾸어주면 된다.
5단계: change value를 누를 때마다 값이 바뀌는데 이 값을 눌러도 바뀌지 않도록 만드는 것이 목표이다. 일단 초기값인 100을 value에 입력하면 변수가 너무 많이 나오기 때문에 값이 저장되어 있는 주소를 찾기 위해 change value를 눌러주어 바뀐 값인 724를 value에 입력해주면, 현재 값이 724이고 초기값이 100인 변수 하나가 나온다. 이를 선택해 우클릭을 해주어 튜토리얼에 나와있는대로 find out what writes to this address를 선택한다. 그런 다음 튜토리얼로 다시 들어가 값 변경 버튼을 클릭하고 다시 돌아오면 나오는 어셈블리어 코드를 아무것도 수행하지 않는 코드로 변경하면 된다. 그러기 위해서는 replace를 선택해 아무것도 수행하지 않는 명령어인 nop를 입력해주고 close를 눌러주면 된다. 그런 다음, 다시 튜토리얼로 돌아와 change value를 한 번 더 눌러주면 5단계가 끝이 난다.
6단계: 포인터를 찾아 값을 5000으로 고정시키는 문제인데, 위의 change value 값을 누르면 포인터가 가리키는 변수의 값이 변경되고, change pointer 버튼을 누르면 포인터의 값이 변경된다. 먼저 change value를 눌러 값을 변경시키면서 현재 주소를 찾은 후에, 찾은 주소를 우클릭해서 Find out what accesses this address 라는 항목을 클릭해 포인터 변수를 찾아야 한다. 탭을 열어 놓고 change value를 눌러주면 어셈블리어 코드가 보인다. 이 중에서 두 번째 코드를 클릭하고 보이는 EDX 값인 0187E6E8 이 포인터 변수가 저장하고 있는 값이라고 생각된다. 다시 돌아와서 value 값에 0187E6E8 를 넣고 16진수인 Hex를 체크 한 다음 스캔해보면 하나의 주소가 나온다. 이 주소를 선택해서 Add Address Manually를 클릭해 포인터 변수를 등록해야 한다. Add Address 창에서 찾은 포인터 변수 값을 입력해 OK 버튼을 클릭하면 포인터가 가리키는 변수의 값을 알 수 있게 된다. 이 값을 선택해 value를 5000으로 바꿔준 뒤 active를 체크해주면 포인터 값이 5000으로 freeze 된다.
7단계: 버튼을 누를 때마다 health 의 값이 1씩 감소한다. 코드 인젝션을 통해 버튼을 클릭할 때마다 2씩 증가시키는 것이 목표이다. health를 눌러 값을 변경시킨 후 변경된 값을 나타내는 주소를 찾고 선택해 Find out what writes to this address 를 클릭한다. 클릭 후 hit me 버튼을 누르면 나오는 코드를 더블 클릭해보면 1씩 빼는 코드를 확인할 수 있다. 그 다음으로 show diassembler 를 클릭해 어셈블리어 코드를 볼 수 있는 창이 나오고, 이 창에서 tool 항목의 auto assemble을 클릭한 다음, template 항목에서 code injection 을 선택해주고 OK를 눌러주면 원래 코드를 확인할 수 있다. 원래 코드에서 1씩 빼는 부분을 2씩 더하는 코드로 바꾸어 적어주고 execute를 눌러주면 누를 때 마다 값이 2씩 증가하게 된다.
8단계: 문제는 특정한 변수를 가르키는 여러 포인터를 찾아 그 값을 5000으로 고정시키는 것이 목표이다. 먼저, change value로 값을 변경시키면서 변수를 발견해 선택한다. 그 후 이 주소를 선택해 find out what accesses this address를 눌러 실행되는 어셈블리어 코드를 확인한다. 어떠한 포인터 변수가 esi 값 정보를 저장하고 있다는 사실을 알게 되어 ESI 값 018D90A0 을 value 에 입력해 찾아 준다. 그 때 나온 주소를 다시 선택해서 다시 실행되는 코드를 확인한다. 이중 포인터를 의미하는 코드를 발견할 수 있다. 이번에는 value 칸에 방금 코드를 분석했던 것의 주소를 입력한다. 입력한 다음, 다시 분석하면, 현재 주소 값에서 14를 뺀 값을 가지고 있는 포인터 변수가 있다는 것을 발견할 수 있다. 그래서 위의 주소에서 14를 뺀 값인 18F1CA8을 value에 입력해준다. 다시 선택해준 후 분석하면 기존의 주소에서 0C를 뺀 값을 가지고 있는 포인터 변수가 있다는 것을 알게 되고, 위의 주소에서 0C를 뺀 값인 18664C0을 value 입력해 스캔하면 시작 포인터를 발견할 수 있다. 이 발견한 포인터를 선택해 add address manually 버튼을 누르고 Add offset으로 다중 포인터 변수를 추가해야한다. 각 칸에 지금까지 계산했던 수를 입력하고 OK버튼을 눌러준 다음 등록된 시작 포인터 변수의 value 값을 5000으로 설정해주고 active를 체크해주어 고정시켜주면 된다.
8단계: 우리 팀인 player 1과 2가 적 팀인player 3과 4와의 싸움에서 이기도록 하면 된다. 게임을 시작하면 각 player의 health가 감소하는데 치트 엔진을 이용해 우리 팀이 이기도록 하는 것이 목표이다. 먼저 Dave의 health 값의 주소를 찾기 위해 Dave 의 attack 버튼을 누르고 변한 수를 value 값에 넣어 스캔을 해서 찾아준다. 주소를 찾았으면 그 주소의 description을 체력값의 주인인 Dave로 바꾸어준다. 그 다음 찾은 주소를 선택해 find out what accesses this address를 눌러주면 mov [ebx + 04] 라는 코드를 확인할 수 있다. 그 후 browse this memory region을 선택해 실행해주어 ebx + 15 의 위치에 이름 데이터의 첫 번째 글자가 나오는 것을 확인한다. 그 후, 어셈블리어를 수정하기 위해 show disassembler을 클릭하고, tool 항목에서 auto assemble을 클릭하고, template 항목에서 code injection을 클릭해주면 4번째 사진의 코드가 나온다. 이 코드를 5번째 사진에 있는 코드처럼 수정해주면 수의 이름 데이터 값이 'D'로 시작하는 경우는 체력 데이터를 감소시키지 않고 바로 종료되도록 만들 수 있다. 이렇게 수정한 후 execute 버튼을 클릭하고 돌아가서 restart game and autoplay 버튼을 눌러보면 실제로 Dave의 체력은 줄지 않고 팀이 승리하는 모습을 볼 수 있다.
Issues
6단계에서 Find out what accesses this address 을 클릭한 후, 아무리 change value 버튼을 눌러보아도 아무것도 안뜨는 일이 벌어졌다. 여러 번 해봤는데도 달라지는 것이 없어 결국 껐다가 켜보니 해결되었다. 그 이후로도 여러 번 이런 현상이 일어나서 여러 번 나갔다 들어왔다.
참고한 자료: https://ndb796.tistory.com/144