ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Lenas Reversing for Newbies] 18
    Wargame/dreamhack.io 2021. 3. 29. 23:59

    1. 프로그램 실행

     

    실행 화면 1

    프로그램을 실행화면 위와 같이 TutorialNag 메시지 박스가 나타난다. 확인 버튼을 눌러보자.

     

    실행 화면 2

    적절한 패치를 통해 '실행 화면 1'의 메시지 박스를 없애면 될 것 같다.

     

    2. Debugging(with OllyDbg)

    OllyDbg로 파일을 열어보자.

     

    디버깅

    바로 아래 004012BD 주소에 CALL MessageBoxA 명령을 통해 MessageBox가 호출되는 듯하다. BP를 걸고 F9를 이용해 프로그램을 실행시켜보자.

     

    디버깅

    하지만 놀랍게도 BP에 적중하지 않는다. 이번 실습의 주제가 Diversion code, encryption/decryption, selfmodifying code and polymorphism임을 생각하며, EP 부터 차근차근 디버깅을 해보자.

     

    디버깅

    GetModuleHandle API를 통해 EAX 레지스터에 ImageBase 값이 저장되고, 403130 주소에 옮긴다. 이후 401299 주소의 CALL ReverseM.0040130F가 호출된다. F7을 눌러 Step in 해보자.

     

    디버깅

    위와 같은 loop가 있는 것을 확인할 수 있다. loop에서는 00401000주소부터 00401314 직전까지 한 바이트씩 5A와 XOR 연산을 한다. 이때 해당 영역은 메모리 맵을 통해 .text(code) 영역임을 확인할 수 있다. 즉 XOR 연산을 통해 코드 영역의 일정 부분을 복호화하는 작업을 진행 중인 듯하다. RETN에 BP를 설정하고 넘어가 보자.

     

    디버깅

    이번에는 00401011 영역으로 이동하게 된다. 해당 영역은 직전에 복호화가 진행된 영역임을 생각하면서 F7을 통해 step in 해보자.

     

    디버깅

    현재 EDI 레지스터에는 00401011 주소가 담겨있으며, MOV / ADD 명령어의 반복을 통해 마찬가지로 코드 복호화가 이뤄진다. 동그라미 표시한 CALL EDI까지 실행해보자.

     

    디버깅

    무언가 메시지 박스를 호출하는 루틴으로 코드가 변경되었다. 동그라미 표시한 부분을 보면 텍스트가 깨져있는 것을 확인할 수 있다. 코드를 천천히 살펴보면 현 위치(00401000) 아랫부분에서 00403000 영역의 복호화가 이뤄지고 있으며, 메시지 박스의 텍스트들이 해당 영역에 존재하는 것을 파악할 수 있다. 우선 복호화 루프까지 실행시켜보자.

     

    디버깅

    위와 같이 지워야 할 Nag 메시지 박스를 호출하는 코드가 나타난다. Nag 박스를 지우기 위해서 메시지 박스가 호출된 직후 Jump 하는 곳으로 호출되기 전에 Jump 하도록 코드를 수정해주면 좋을 것 같다. JMP SHORT 이므로 문제에서 요구하는 two byte patch에도 적합한 방법이다.

     

     그런데 패치를 하기에 앞서 주의해야 할 부분이 있다. 바로 00401011 주소를 JMP 0040106A로 패치하면 좋겠지만, 00401000 ~ 00401314 영역은 복호화를 거친 코드이므로, 암호화된 상태에서 복호화된 코드가 JMP 0040106A가 되도록 코드를 패치해야 한다. 00401011 주소의 PUSH 0 명령어가 어떤 과정으로 생성되었는지 역으로 추적해보자.

     

    디버깅

    이전의 두 번째 복호화가 이뤄지기 직전의 상태이다. EDI 레지스터에는 00401011의 주소가 들어있고, 00401013 주소의 MOV WORD PTR DS:[EDI],6A 명령어를 통해 6A 00이 401011 주소에 들어가게 되고, 이 부분이 바로 PUSH 0 명령어가 된다. JMP 0040106A의 opcode를 살펴보자.

     

    디버깅

    위와 같이 6A 00 -> EB 57로 바뀌어야 한다. 그렇다면 MOV WORD PTR DS:[EDI], EB57로 바꾸면 되는 것일까? 해당 명령어는 역시 첫 번째 복호화에 의해 변화한 코드이므로 마찬가지로 복호화를 고려해주어야 한다. 첫 번째 복호화에서는 5A를 바이트 단위로 복호화하였으므로 00401016 ~ 00401017 주소의 값에 5A를 XOR 했을 때 EB 57로 바뀌도록 코드를 패치해야 한다. XOR 연산의 성질을 이용해서 EB 57에 5A를 XOR 하게 되면 B1 0D가 된다. 프로그램을 재실행한 후, 00401016, 00401017 주소의 값을 B1 0D로 수정한 후 저장하고, 프로그램을 실행해보자.

     

    패치 성공

    위와 같이 더 이상 Nag 메시지 박스가 안 나타나는 것을 확인할 수 있다.

     

    3. Comment

    간단하면서 복잡한(?) 문제였다. 메시지 박스를 지우기 위해 당연히 API에 BP를 설정하고 패치하는 방법을 생각했었는데, encryption/decryption 때문에 동적 분석을 진행하기 전에는 코드의 흐름을 파악할 수 없었다. 각종 바이러스 또는 악성 툴에도 위와 같은 기법이 적용되기도 한다고 한다.

    반응형

    댓글

Designed by Tistory.