Using Breakpoints
1. 접근
리버싱을 위해서는 보고 싶은 정보가 무엇인지 파악한 다음, 어디에 해당 정보가 있는지 찾아야한다.
예를 들어 게임이 특정 작업을 수행할 때 표시되는 텍스트를 검색하고 싶다면, 메모리 편집기에서 찾은 메모리 주소를 사용하여 코드를 찾을 수 있다.
이러한 접근 방식에서는 breakpoint를 사용하게 된다.
2. breakpoints
중단점을 사용하면 디버거가 특정 명령에서 게임 실행을 일시 중지하고, 사용자는 게임의 메모리를 볼 수 있다.
모든 유형의 메모리에 중단점을 설정할 수 있으며 메모리 스캐너를 사용하여 찾은 메모리도 대상에 포함된다.
중단점은 조건부, 비조건부로 설정 가능하며 해당 조건이 충족되는 경우에만 트리거된다. (=팝핑)
3. Memory Breakpoints
메모리 해킹 게시물에서 우리는 골드의 메모리 위치를 찾을 수 있었다.
이 때 골드를 사용하는 시점에 중단점을 걸어 실행을 일시 정지 시켜보도록하자.
mov eax, dword ptr ds:[0x05500ABC]
mov ebx, dword ptr ds:[0x12345678]
sub eax, ebx
-> mov dword ptr ds:[0x05500ABC], eax
mov esi, ebx
먼저 0x05500ABC 에 저장된 값(골드 위치)을 eax로 이동하고
단위 비용에 대한 가상 값을 ebx로 이동한다.
다음으로 사용한 골드를 차감하는데 일시 정지된 위치는 새로운 골드를 '골드 저장 메모리 위치'로 다시 이동하는 역할을 담당한다.
차감 과정에서는 게임이 일시 정지되지 않은 것을 볼 수 있는데 이는 작업이 레지스터 값만 수정하고 중단점을 설정한 실제 메모리의 값은 수정하지 않기 때문이다.
중단점은 영향을 받은 메모리 바로 뒤 명령에서 항상 일시 중지된다.
4. Code Breakpoints
중단점을 설정할 메모리 값을 찾을 수 없다면 코드 섹션에 중단점을 설정할 수도 있다.
일반적으로는 텍스트 참조에 중단점을 설정하고 이를 통해 관심 있는 최상위 함수를 찾는 것으로 진행된다.
ex)
void main_loop(){
draw_players();
draw_walls();
...
}
wallhack의 메인루프
void draw_walls(){
bool succeeded = load_texture("wall_texture");
if(succeeded == false){
print_error();
}
}
draw_wall 함수
void print_error(){
print_to_log("Couldn't find wall texture");
}
print_error 함수
wallhack을 작성하는 방법으로 이 게임의 draw_wall 기능을 제거하는 것이 있다.
위 환경에서는 메모리 중단점으로 사용할 변수가 없으므로 코드 중단점을 사용해야한다.
mov eax, dword ptr ds:[0x23456789]
push eax
call print_to_log
...
이 코드 섹션은 문자열을 레지스터에 로드한 다음 print_to_log 함수를 호출한다.
이 코드에 중단점을 설정하고 누락된 텍스쳐를 찾으면 중단점이 나타나고,
코드를 호출한 함수로 반환할 때까지 단계별로 실행하다보면 함수를 벗어날 수 있는데
밖으로 나간 후에는 draw_wall 함수에 있게 되며 함수를 제거할 수 있다.
5. nop instruction
nop(opcode, 0x90)는 작업이 없음을 나타낸다.
이 명령어를 만나면 cpu는 아무것도 하지 않고 다음 명령어를 계속 진행한다.
예를 들어 메모리 중단점 섹션에서 골드가 차감되는 코드를 nop로 대체하면 게임에서 골드가 더 이상 차감되지 않는다.