FSC_level2
FSC_level1은 리버싱대회라기엔 너무 쉬운 난이도 였다.
FSC_level2문제를 풀어보자!!
FSC_level2를 시작하면 실행되는 창이다. 이렇게 창만 뜨는 경우에는 일단, 실행했을 때 저 화면과 다른 또 다른 메시지가 나와야 하는 것이 아닐까????라고 추측해 볼 수 있어야 한다.
그렇다면 어떻게 실행해야 또 다른 제 2의 화면이 나올 수 있을까???(리버스엔지니어링 바이블에 의하면)
1.같은 폴터에 어떤 파일이 담겨 있어야 제대로 실행된다.
2.현재 프로세스 리스트 가운데 특정 문자열이 담긴 프로레스가 띄워져 있어야 한다.
3.현재 윈도우 리스트 가운데 특정 캡션명을 지닌 윈도우가 떠 있어야 한다.
4.LEVEL_2문제가 실행될때 특정 파라미터를 지정해서 실행해 주어야 한다.
1번과 같은 경우라면 CreatFile() 같은 API가 사용될 것이다.
2번과 같은 경우라면 OpenProcess()나 Process32Next()등이 보일 것이다.
3번과 같은 경우라면 FindWindow()
4번과 같은 경우에는 GetCommandLine()등을 반드시 이 바이너리에서 사용해야 한다.
리버스 엔지니어링 바이블에 적혀있는대로라면 이와 같은 API가 쓰였을 것이다. PEheader를 살펴도록 하자!!
GetCommandlineA()함수가 보여진다. 따라서 파라미터를 프로그램을 열때 지정해주어야 한다는 것을 짐작할 수 있게 되었다.
또한 UPX로 패킹되어 있다는 것도 알 수 있게 되었다. 언패킹 후 파라미터 abcd를 지정 후 실행!!!!!!!!!!!
이 loop부분에서는 level_2문제를 실행한 경로+파라미터의 주소를 가진 EDX을 +1씩 연산하여 한 byte씩 이동시겨 다음 byte를 가리키도록 한뒤 XOR EAX 연산으로 EAX의 값을 0으로 초기화 시킨다음 CMP 구문으로 점프하거나 진행하게 된다. EDX는 계속해서 한 BYTE씩 옮겨져서 마지막에는 abcd의 뒷부분 NULL문자열을 가리킨다. 이러한 상황이 되면 loop문을 탈출하게 된다.
요약해서 정리하자면....
BYTE [EDX-5]와 0x20을 비교 //이는 파라미터가 4byte인가를 확인하는 작업이다.
abcde를 입력한 경우 EDX-4는 a가 되므로 정상적으로 진 행할 수가 없다.(0x20은 spacebar)
MOV EAX,DWORD PTR DS:[EDX-4] //EDX-4는 a를 가리킨다. DWORD단위이므로 abcd
XOR EAX,5528566D //EAX, 즉 abcd를 5528566D와 XOR연산한뒤 EAX에 저장
XOR AH,BH //위의 연산결과의 AH를 BH와 XOR한다.
MOV EAX,DWORD PTR DS:[EDX-A] //EDX-A는 .이며 DWORD이므로 .exe이다.
CMP EAX,DWORD PTR SS:[ESP] //디버거로 확인해보면 EAX에는 .exe가 들어가 있고,
ESP에는 위의 AH와 BH의 XOR연산결과가 들어가 있다.
임의로 ZF를 1로 바꿔 위의 두 값이 같다면 어떻게 되는지 보았다.
성공메시지!!!가 뜬다. 따라서 위의 값이 같도록 파라미터를 설정해주면 된다는 것을 알 수 있다.
따라서 정리해 보면
-내가입력한 파라미터 XOR 5528566D
-AH XOR BH (BH는 E0이 들어있음)
-위의 값이 .exe값과 같아야함
여기서 .exe의 값은 6578652E이다. 따라서 계산을 해보면 XOR연산의 특징에 따라 6578652E의 65부분과 BH의 값 E0을 XOR연산을 한 후 그 값을 5528566D와 XOR한 값이 정답이 될 수 있음을 알 수 있다. (A XOR B의 값이 C일 때 C XOR A의 값은 B라는 특징)
연산결과: 3050D343이 나온다. 따라서 파라미터의 값은 43 D3 50 30 (리틀엔디안)이다.
아스키코드표에 따라 43은 C D3 ?? 50은 P 30은 0임을 알 수 있다 하지만 D3는 아스키코드로 나타낼 수가 없다.
여기서 굉장히 고민을 하고 구글링을 하기 시작했다.
마침내 찾아낸 것이 TLS Callback이라는 안티디버깅 기법이다. 이 TLS Callback 이라는 안티디버깅 기술은 스레드가 생성될 때 로더에 의해서 실행되는 코드이며, 보통 디버거를 이용하여프로그램을 오픈하면 엔트리 포인트에서 프로그램이 멈추는데, TLS callback은 프로그램의 엔트리 포인트 이전에 실행되어 디버거로 분석하기가 쉽지않은 특징을 가지고 있다고 합니다.
UPX를 언패킹했을 때 이 TLS Callback 함수는 날라가버려 분석하기가 어렵게 됩니다. 따라서 UPX를 언패킹하지 않은 상태에서 IDA를 실행시키면 TLS Callback함수를 보여줍니다. (IDA는 똑똑한 디버거 이기 때문이다. 또한 PE header를 봐도 알수가 있다.)
이렇게 TSL callback함수를 볼 수가 있다
UPX2:004070AC mov eax, large fs:18h
UPX2:004070B2 mov eax, [eax+30h]
UPX2:004070B5 movzx eax, word ptr [eax+2]
UPX2:004070B9 cmp eax, 0 TLS Callback 내부의 함수에서 이런 코드를 볼 수가 있는데 이는 IsPresentDebuger를 옮겨다 놓은 코드이다.
밑에 SETZ 코드는 Z가 1일때 AL을 1로 바꾸어 주는 어셈블리 명령이다.
imul은 곱 어셈블리 명령이며 imul eax, 8은 eax * 8이 된다. 따라서
디버깅 중이 아니라면 sub byte ptr ds:loc_4063BC+1, al 에서 al은 0이 되고
디버깅 중이라면 sub byte ptr ds:loc_4063BC+1, al 에서 al은 8이된다. byte ptr ds:loc_4063BC+1에서 4063BC+1이 무엇일까????
UPX에 별다른 조작을 하지 않았다면 UPX1의 섹션의 마지막 JMP 명령에서 점프하는 곳이 프로그램의 OEP가 된다. 그렇다면 디버깅 중이 아니도록 eax를 0으로 바꾸면 sub byte ptr ds:loc_4063BC+1, 8(al)의 명령과 같아진다. 4063BC에 있는 주소값이 4BYTE JMP가 1BYTE이므로 결국 저 연산은 JMP 주소값을 변환 시킨다. 따라서 40135A - 8 = 401352로 엔트리 포인트를 지정해 주면 될 것같다.(맨첨 Ollydbg로 열었을 때 엔트리 포인트는 40135A였다.)
TSL callback에 의해서 0040185A는 원래 00401852를 먼저 실행한 후에 지나쳐야 하는데 지나치지 않고 실행되어 EBX에 잘못된 값이 들어있었던 것이다. (00401352 > . 33DB XOR EBX,EBX) 따라서 정상적으로 계산하면 C3P0이라는 파라미터를 넣어주어야 한다는 것을 알 수가 있다.
0 개의 댓글