1. 정보 수집

  • 실행하면 위와 같은 메시지를 출력하고 종료되는 실행파일이다.

  • PEiD를 이용하여 해당 바이너리의 패킹 여부를 확인한다.

  • UPX 패킹된 바이너리임을 확인할 수 있었다.

  • upx 리눅스 유틸리티를 이용하여 언패킹을 진행

  • 언패킹된 바이너리


  1. 분석

  • IAT 테이블을 살펴보니 다음과 같이 command line을 읽어오는 함수가 존재했다.

  • 따라서 해당 바이너리를 정상 작동시키기 위해선 command line의 실행 인자를 전달해줘야 할 것이라고 추측이 가능하다.

  • GetCommandLine 함수 직후에 특정 반복문이 존재하고 해당 반복문은 Command line으로부터 읽어들인 문자열을 edx 레지스터가 1바이트씩 이동하여 마지막 바이트를 가리키도록 한다.

  • 이후 AL 레지스터에 [EDX-5] 위치의 1 바이트를 옮기고 해당 값을 스택에 넣는다.

  • AL 레지스터에 0x20의 값을 넣고 스택의 최상단과 비교한다.

  • 즉 EDX-5 위치가 0x20(공백문자)와 일치한지를 비교한다.

  • 이후 일치하지 않을 0x004012FC 주소로 점프하며 해당 주소는 다음과 같이 MessageBox API를 호출하며 처음 출력되는 메시지가 출력된다.

  • 따라서 해당 출력문을 피하기 위해선 [EDX-5]가 공백문자여야 하므로 파라미터는 다음과 같이 뒤에서 5번째 문자가 공백문자인 4글자의 파라미터가 전달되어야 한다.

    C:\Users\Desktop\FSC_Level2.exe asdf

  • 인자로 "asdf"를 전달하고 해당 조건을 만족시키도록 하고 해당 분기문에 bp를 걸고 나머지를 분석한다.

  • 이후 또 다시 비교문과 해당 비교문이 만족하지 않을 경우 비정상 종료 루틴에 빠지는 부분을 발견했다.

  • 해당 위치에서 EAX에 0x6578652E(".exe")를 넣고 해당 값을 스택의 최상단에 있는 값과 비교한다.

  • 해당 위치로 오기까지 스택의 최상단에 어떤 값이 위치하는지 확인하기 위해 백트레이싱을 수행한다.

  • 인자로 전달한 0x66647361("asdf")을 0x5528566D과 xor 연산을 수행한 결과를 EAX에 저장한다.

  • EAX에는 0x334C2501이 저장됨

  • AH(0x25)와 BH(0xC0)를 XOR 연산을 수행하여 0x334CE50C이 EAX에 저장된다.

  • 이후 해당 값을 0x6578652E(".exe")와 비교하여 일치하지 않을 경우 실패 루틴으로 진입한다.

  • 따라서 0x6578652E의 값에 일련의 과정을 역연산해주고 나온 값을 파라미터로 전달할 경우 성공 루틴으로 진입이 가능하다.

  • 0x6578652E의 세 번째 바이트인 0x65와 0xC0를 xor한 결과인 0x6578A52E

  • 해당 값을 0x5528566D와 xor한 결과 = 0x3050F343

  • 확인한 결과 실행할 때마다 ebx의 값이 변함

  • ebx의 값을 설정하는 코드를 찾아본 결과 다음과 같이 entry 포인트에 존재

  • 그러나 해당 지점에 bp를 걸고 실행해도 해당 부분은 실행되지 않음

  • 원래대로라면 ebx에 고정된 값인 0으로 초기화되고 xor 연산에 영향을 주지 않아 "C3P0"가 정답이 되어야 하는데 안티디버깅 기법이 있는 것으로 볼 수 있음

  • 실행 과정에서 ebx를 강제로 초기화하고 인자를 "C3P0"로 전달할 경우 정상적으로 플래그가 출력됨

    정리

    • PEP와 OEP : Packing entry point, Original entry point

    • PEP 코드 실행 도중 디버거 사용 유무를 탐지하여 사용중일 경우엔 다른 OEP에서 시작하도록 하는 기법이었음

    • 해당 문제에서는 TLS(Thread Local Storage) callback을 이용한 기법을 사용함

    • TLS Callback이란 프로세스가 만들어질 때 메인 쓰레드가 초기화되기 전에 가동되는 코드

    
    • PE header를 참조한 결과 해당 TLS 코드가 0x4070DC 번지에 존재함

    • TLS callback 함수에 존재하는 디버거 탐지 코드 (IsDebuggerPresent())

    • 따라서 디버거가 붙을 경우에 xor ebx, ebx 구문을 피해서 ebx가 초기화되지 않도록 하여 정상적인 플래그 인증에 실패하도록 하고 디버거가 붙지 않았을 겨웅 xor ebx, ebx가 정상적으로 실행돼서 플래그 인증이 가능하다.




















+ Recent posts