1. 질문
8단계: 다단계 포인터: (PW=525927)
이 단계에서는 다단계 포인터를 사용하는 방법을 설명합니다.
6단계에서는 간단한 레벨 1 포인터를 사용했는데, 첫 번째 주소가 이미 실제 기본 주소였습니다.
그러나 이 단계는 레벨 4 포인터입니다. 여기에는 포인터에 대한 포인터에 대한 포인터에 대한 포인터에 대한 포인터에 대한 포인터가 있습니다.
기본적으로 6단계와 동일한 작업을 수행합니다. 값에 액세스 하는 것이 무엇인지, 인스트럭션과 기본 포인터 값은 무엇인지, 오프셋은 무엇인지 알아내고 이미 입력하거나 적어두면 됩니다. 하지만 이 경우 찾을 수 있는 주소도 포인터가 될 것입니다. 값과 똑같은 방법으로 해당 포인터에 대한 포인터를 찾기만 하면 됩니다. 찾은 주소에 액세스 하는 방법을 찾아 어셈블러 인스트럭션을 살펴보고 가능한 인스트럭션과 오프셋을 메모한 다음 이를 사용하세요.
더 이상 얻을 수 없을 때까지 계속합니다(일반적으로 기본 주소가 녹색으로 표시되는 정적 주소인 경우).
값 변경을 클릭하여 튜토리얼이 상태에 액세스 할 수 있도록 합니다.
포인터 경로를 찾았다고 생각되면 변경 등록을 클릭합니다. 그러면 포인터와 값이 변경되고 3초 동안 주소가 5000으로 고정됩니다.
추가: 이 문제는 자동 어셈블러 스크립트를 사용하거나 포인터 스캐너를 사용하여 해결할 수도 있습니다.
추가2: 다음과 같은 경우 CE의 코드파인더 설정을 액세스 위반으로 변경하는 것이 좋습니다.
다음과 같은 명령어가 발생하면 디버그 레지스터에 변경된 후에 표시되므로 포인터의 값을 찾기가 어렵습니다.
추가3: 아직 읽고 계신다면. 어셈블러 명령어를 보면 동일한 코드 블록에서 포인터가 읽혀지고 채워지고 있다는 것을 알 수 있습니다(동일한 루틴, 어셈블러를 알고 있다면 루틴 시작 부분까지 찾아보세요). 항상 이런 일이 발생하는 것은 아니지만 디버깅이 번거로울 때 포인터를 찾는 데 매우 유용할 수 있습니다.
- 이전 step에서 포인터를 찾은 것처럼 이번엔 포인터의 포인터의... 근원 포인터를 찾아 값을 고정시켜주어야 한다.
2. 분석 과정
먼저, change value 버튼을 사용하여 값의 변화를 관찰하며 변수의 주소를 찾는다.
변수의 주소는 10A5E8이며, 이제 이 변수에 접근하는 포인터의 흐름을 따라가 본다.
해당 주소에 쓰기 위해 접근하는 목록을 확인한다.
해당 어셈블리 코드의 의미는 "rsi 값에 + 18 한 값"을 주소로 삼아 그곳에 eax 값을 저장하라는 것이다.
- RSI 레지스터는 x86-64(또는 x64) 아키텍처에서 사용되는 범용 레지스터 중 하나입니다. RSI는 "Source Index"라는 의미로, 주로 메모리 작업에서 소스 주소를 지정하는 데 사용됩니다.
RSI의 값은 10A5D0로 이제, 이 RSI 값을 갖고 있는 포인터를 검색한다.
187500이라는 주소에 10A5D0이 저장되어 있음을 확인하였다.
- 첫 번째 포인터 변수의 주소 187500
더블클릭하여 주소록에 추가하고, 이제 해당 포인터를 가리키는 다음 포인터를 찾기 위해 해당 주소에 접근하는 목록을 확인해 본다.
mov rsi, [rsi]라는 어셈블리 코드를 확인할 수 있으며, 이 코드의 의미는 rsi에 저장된 값을 주소로 삼아 해당 주소가 가리키는 내용을 다시 rsi에 저장하라는 의미이다. 그렇게 저장된 rsi 값이 10A5D0이다.
거꾸로 추적하면, 10A5D0를 저장한 ‘187500 주소 값’이 저장된 주소(아래그림의 물음표)가 우리가 찾아야 할 다음 포인터라는 의미이다. 이렇게 포인터의 주소가 저장된 포인터 변수를 이중 포인터라고 한다.
First scan 기능으로 187500을 찾는다. 결과가 나오지 않는다면 change value를 눌러가며 진행한다.
187498 주소에 187500이 저장되어 있었다. 더블클릭하여 주소목록에 추가한다.
- 두 번째 포인터 변수의 주소 187498
다음으로, 187498 주소에 접근하는 목록을 탐색해 보자. 아까와 같이 Find out what accesses this address 메뉴를 클릭한다.
Mov rsi, [rsi+18] : rsi+18 값을 주소로 삼아 해당 주소에 있는 값을 RSI에 저장한다. 저장의 결과는 187500이다.
그렇다면 역으로 187500 값을 저장한 주소에 18을 빼서 검색한다면 다음 포인터를 알 수 있을 것이다.
187498-18 = 187480을 검색해 본다.
검색을 하니, 109B00가 187480을 저장하고 있었다. 더블클릭하여 주소목록에 저장한다.
- 세 번째 포인터 변수의 주소 : 109B00
계속해서 같은 일을 반복한다. 해당 주소에 접근하는 목록을 불러와 어셈블리 코드를 확인한다.
mov rsi, [rsi+10]
이번엔 오프셋이 "10" 이므로 현재 주소인 109B00에 10을 뺀 109AF0 값을 검색해 본다.
최종 포인터 주소인 100325B00가 결과로 나왔다. 더블클릭하여 주소목록에 추가하자.
- 네 번째 포인터 변수의 주소 : 100325B00
이제 근원 포인터 주소를 알았으므로 이 포인터들을 추적하는 포인터를 수동으로 추가해 준다.
결과로 나온 마지막 주소에 커서를 두고 Add Address Manually를 클릭하거나, 주소부분을 더블 클릭한다.
지금까지 거쳐왔던 포인터들의 오프셋을 입력한다. (오류로 인한 재수행으로 주소가 지금까지 진행해 왔던 것 과 다른 점 양해 부탁드립니다.)
상단 "=389"는 현재 change value 값을 나타낸다. 같게 나온다면 제대로 오프셋을 설정했음을 알 수 있다.
만약 16진수로 표기된다면 Hexadecimal 표시를 체크 해제 한다.
생성을 완료했으면 value 값을 더블클릭하여 값을 5000으로 바꾸어준 뒤 고정한다.
Change pointer을 눌러 값이 고정되어 있는지 확인한다.
성공한다면 NEXT버튼이 활성화된다.