Reversing/Reversing2017. 6. 26. 21:03

선수 지식

Stub Code: 컴파일러마다 필요한 코드를 추가해놓은 것. 코드 상으로는 “Hello World”라는 메시지를 출력하는 것만 있을지라도, 그 코드가 동작하기 위해서 필요한 부가적인 코드를 컴파일러가 추가해서 Release한다.

 

 

OllyDbg 기본 명령어

Restart [Ctrl+F2]: 처음부터 디버깅 다시 시작 (디버깅을 당하는 프로세스를 종료하고 재실행)

Step Into [F7]: 하나의 OP Code 실행(CALL 명령을 만나면, 그 함수 코드 내부로 따라 들어감)

Step Over [F8]: 하나의 OP Code 실행(CALL 명령을 만나면, 따라 들어가지 않고 그냥 함수 자체를 실행함)

Execute till Return [Ctrl+F9]: 함수 코드 내에서 RETN 명령어까지 실행(함수 탈출)

 

※ OllyDbg를 켜면 동작중인 디버거가 발견되었습니다. 디버거를 종료한 후 다시 실행하시기 바랍니다라는 경고문구가 뜨는 경우가 있는데, 제어판에서 Delfino를 언인스톨해주면 정상적으로 OllyDbg를 사용할 수 있다.

 

 

Hello, World! 디버깅

Hello, World 프로그램의 소스코드는 다음과 같다.

릴리즈 하고 OllyDbg 위에 올려서 한 줄씩 따라간다. 오른쪽에 OllyDbg가 적어준 코멘트를 잘 확인하면서 굳이 들어갈 필요 없어보이는, 즉 컴파일러의 Stub Code로 보이는 부분들을 CALL하는 명령을 Step Over로 넘어가다 보면 아래와 같은 함수로 들어올 수 있다.

위 함수는 우리가 작성했던 Hello, World! 코드에 작성한 문자열이 맞으므로, 우리는 main함수를 제대로 찾아왔음을 알 수 있다.

 

※ 디버깅 도중 알 수 없는 명령이라 실행할 수 없다는 경고가 뜨는 경우가 있는데, [Option – Debugging Options - Security]에서 아래 ‘Allow stepping into unknown commands’에 체크해주면 정상적으로 디버깅이 가능하다.

 

 

BaseCamp 설치 및 원하는 코드 빨리 찾기

BaseCamp를 설치하는 방법에는 다음 네 가지가 있다.

1.     Goto 명령 사용 [Ctrl+G]

2.     BP(Break Point) 설치 [F2]

3.     주석 [;(세미콜론)]

4.     Label 달기 [:(콜론)]

OllyDbg는 디버깅할 프로그램을 처음 로딩할 때 사전 분석 과정을 거친다. 프로세스 메모리를 훑어서 참조되는 문자열과 호출되는 API를 뽑아내어 따로 목록으로 정리를 해놓는데, 이는 디버깅 과정에서 큰 도움이 된다.

위와 같이 Text String으로도 원하는 곳을 찾아갈 수 있다.

위에서 ‘All intermodular calls’를 선택하면 프로세스에 로드된 API 목록을 볼 수 있다.

하지만 Packer Protector를 사용해 실행파일을 압축하거나 보호해버리면 파일의 구조가 변경되어 API 호출 목록이 보이지 않게 된다. 이럴때는 프로세스 메모리에 로딩된 라이브러리(DLL 코드)에 직접 BP를 걸어준다.

[Alt+M]으로 메모리 맵을 열어보면 HelloWorld 프로세스 메모리의 일부분을 보여준다.

2번에 표시된 부분이 USER32 라이브러리가 로딩 되어있는 메모리 영역이다.

아래는 Name in All Modules 명령을 사용하는 예시이다.

Name in all modules 명령을 선택하고 ‘messageboxw’라고 입력하면 저렇게 USER32 라이브러리에서 로딩된 MessageBoxW라는 함수를 찾을 수 있다. 더블클릭하면 USER32.dll에 실제로 구현되어 있는 MessageBoxW 함수를 볼 수 있다.

위는 USER32.dll MessageBoxW 코드이다. 코드의 시작부에 BreakPoint를 걸어주고 다시 실행해보면 예상대로 표시해둔 BP에서 멈추는 것을 볼 수 있다.

이 때 레지스터의 ESP 값이 프로세스 스택의 주소이다.

 

 

문자열 패치

위와 같이 Main 함수의 시작에 BP를 걸어둔다.

 

1.     문자열 버퍼를 직접 수정

MessageBoxW 함수의 전달인자의 문자열인 “Hello, World!” 버퍼를 직접 수정하는 방법이다. 덤프 창에서 Goto[Ctrl+G]로 해당 주소로 가서 마우스로 선택한 후 [Ctrl+E] Edit 다이얼로그를 띄워 수정한다.

여기서 주의할 점은, “Hello, World!”보다 “Hello Reversing” 문자열이 더 긴데, 일반적으로 원본 문자열 뒤에 어떤 다른 데이터가 있을 수 있으니 원본 문자열 길이를 넘어가는 문자열로 덮어쓰는 것은 위험하다는 것이다.

명령어는 그대로이지만 전달하는 파라미터의 내용 자체가 변경된 것이고, 전달되는 파라미터의 주소 자체는 변경되지 않았다.

이어서 [F9]를 눌러 실행시켜보면 “Hello Reversing”으로 바뀐 것을 확인할 수 있다.

버퍼 내용을 직접 수정하면 간단하다는 장점이 있지만, 기존 문자열 버퍼 크기 이상의 문자를 입력하기 어렵다는 단점이 있다.

바뀐 내용으로 새로운 실행파일을 만들고 싶다면 Copy to Executive File 명령을 사용하면 된다.

 

2.     다른 메모리 영역에 새로운 문자열을 생성하여 전달

원본보다 더 긴 문자열로 패치해야 한다면, 버퍼 내용을 직접 수정하는 방법보다는 다른 메모리 영역에 새로운 문자열을 생성해서 그 주소를 전달하는 방법이 더욱 요긴하다.

위에서 “Hello, World!” 문자열이 있는 주소를 직접 넘겨주는 것을 확인했을 것이다. 그렇다는 것은, 넘겨주는 주소를 우리가 원하는 문자열이 있는 주소로 바꿔주게 되면, 우리가 원하는 문자열이 전달될 것이라고 생각할 수 있다.

아까 덤프 창에서 찾아갔던 주소를 다시 찾아가서 스크롤을 조금 아래로 내리면, 아래와 같이 NULL Padding 영역을 확인할 수 있다.

NULL Padding 영역은 프로그램이 사용하지 않는 메모리 영역이다. 이 부분에 우리가 원하는 문자열을 입력해주고, 문자열이 시작되는 메모리 주소를 아래와 같이 파라미터로 넘겨준다.

이렇게 어셈블한 후 실행시키면 다음과 같이 바뀐 것을 확인 할 수 있다.

그런데 여기서 주의할 점이 있다. 이렇게 수정한 코드는 아까 문자열 버퍼를 직접 수정했을 때처럼 Copy to Executable File 명령으로 새로운 .exe 파일을 생성했을 때 바뀐 문자열이 정상적으로 출력되지 않는다. 그 이유는 우리가 전달한 메모리 주소 때문이다.

파일이 메모리에 로딩되어 프로세스로 실행될 때 파일이 수정한 당시의 메모리 주소대로 메모리로 로딩되는 것이 아니라, 어떤 규칙에 의해서 올라가게 된다. 그 과정에서 프로세스 메모리는 존재하는데, 그에 해당하는 파일의 Offset이 존재하지 않는 경우가 많다. , 우리가 전달해준 메모리 주소에 해당하는 Offset이 존재하지 않는 것이다.

 

'Reversing > Reversing' 카테고리의 다른 글

Calling Convention (함수 호출 규약)  (0) 2017.07.02
Abex’ Crackme #2  (0) 2017.06.30
Stack Frame  (0) 2017.06.27
Abex' Crackme #1  (0) 2017.06.27
OllyDbg Commands & Assembly Basic & etc  (0) 2017.06.27
Posted by BinZIP