아래 문제와 매우 유사하다. 설명이 이 포스팅보다 좀 더 자세하다..
https://hec-ker.tistory.com/123
일단 압출을 풀고 19.exe 파일을 더블클릭하여 실행시켜 보자.
위와 같은 메시지가 뜨고 몇 초 뒤 자동으로 꺼진다.
그 '몇 초'를 찾으면 될 것 같다.
PEiD로 일단 패킹 여부를 검사해봤다.
UPX로 패킹되어 있다.
upx.exe -d 19.exe: 언패킹 완료
언패킹한 파일을 올리디버거에서 열어, 실행시켜봤다.
아까와는 다른 메시지가 출력되고, 리턴되었다.
메시지를 다시 보자.
AutoIt으로 컴파일된 스크립트라고 한다. 물론 파일 썸네일에서부터 알 수 있었다.
어쨌든 오토잇으로 디버깅된 실행 파일이므로 이런 메시지가 뜨는 것 같은데
처음 더블클릭했을 때 나온 메시지 창이 나오지 않고 바로 리턴되는 것을 보니
우린 이 오토잇 출력창이 안나오게 해야한다. 한마디로 안티 디버깅
안티 디버깅하면 떠오르는 함수가 있다. IsDebuggerPresent
일단 이 프로그램에 사용된 함수 목록 중에 IsDebuggerPresent가 있는 지 찾아볼 것이다.
우클릭 후 아래 경로로 들어가면 함수를 볼 수 있다.
예상대로 있었다.
0040E961, 004189F0, 00426997에 IsDebuggerPresent 함수가 쓰인다고 한다.
각각에 BP를 걸고 다시 실행해보자.
이쯤에서 IsDebuggerPresent()에 대한 이해가 필요하다.
이 함수는 해당 프로세스가 디버깅을 당하고 있는지 알려준다. 디버깅 당하고 있으면 리턴값은 1이, 아니면 0이 된다.
일단 걸린 라인은 0040E961, 여기서 IsDebuggerPresent 함수를 호출한다.
그 밑 라인을 보자. TEST EAX, EAX. - JNZ
TEST EAX, EAX는 EAX와 EAX를 AND 연산한다는 뜻이다. 같은 값 AND 연산이므로 1이 리턴될 것이다.
1이 리턴되면, ZF는 0이 된다.
JNZ는 리턴값이 0이 아닐 때, 즉 ZF가 1이 아닐 때 = ZF가 0일 때 점프한다.
따라서, 라인 순대로 004339DE로 점프하고 예상대로 004339DE에는,
아까 그 메시지가 있다.
우린 안티디버깅이 목적이므로, TEST를 수정해 ZF를 1로 만들어 점프하지 못하게 할 것이다.
간단하게 CMP로 수정하자. CMP는 TEST처럼 비교하는 역할이지만 AND 연산 대신 빼기 연산을 한다.
즉 리턴값은 0이 되고 ZF는 1이 되어 점프하지 않는다.
이렇게 수정 후 다시 실행해보면 처음과 같은 메시지가 뜬다.
자 이제 다시 처음으로 돌아가서, 몇 밀리 세컨드 후에 종료되는지를 찾아보자..
아까와 같은 방법으로 사용된 함수 목록을 보면, timeGetTime이라는 함수를 볼 수 있다.
timeGetTime 함수는 윈도우가 시작된 후 지난 시간을 리턴하는 함수다 = 우리가 잘 봐야할 것
찾은 timeGetTime 함수에 BP를 걸었다.
다시 실행시켜보면, 00444C444에서 걸린다.
여기서 timeGetTime 함수가 사용된다.
CALL EDI인 것을 보니 EDI 호출 = timeGetTime 호출인 듯 하다.
여기서 시간과 관련된 함수를 쓰니, 라인대로 쭉 내려가보자.
EDI 호출 후에는 00444C4D에서 EAX의 값을 ESI에 넣는다.
이제 ESI에는 timeGetTime의 리턴값이 들어있다.
그 다음으로는 JE. 같으면 00444D54로 점프한다.
00444D54에서는 EDI를 POP한다. 아까 그 함수다. 아무튼 점프는 하지 않는다.
그 다음은 [ESP+14]의 값을 EBX에 넣는다. EBX는 033C0048의 값을 가진다.
다음으로, Sleep 함수가 실행된다.
아까 시간 관련 함수라고 timeGetTime만 봤는데 Sleep을 간과한게 아찔하다
아무튼.. 다음
이번엔 00444C5F에서 EDI를 다시 CALL한다. timeGetTime 함수를 다시 호출하는 것이다.
그리고 EAX와 ESI를 비교해 JNB 처리한다. JNB 처리는 일단 나중에 보고 먼저 EAX, ESI부터 살펴보자.
서로 비교할 ESI와 EAX의 값은 아래와 같다.
EAX가 ESI보다 크다.
다시 정리하자면, ESI는 처음 timeGetTime 함수를 호출하고 난 뒤 리턴값을 저장했었고
그 뒤 timeGetTime 함수는 다시 호출 됐는데, 그 때의 리턴값을 EAX에 넣었었다. 큰게 당연하다.
비교 후에는 JNB 처리된다. EAX가 더 크므로, 00444D38로 넘어간다.
00444D38에서는 예상대로 EAX와 ESI의 차를 구한다.
이 값이 이 프로그램의 실행시간인지는 확실하지 않지만, 두 시점 사이 시간을 구하고 있으니 유의미해 보인다.
그런데 갑자기 EBX+4와 그 차(EAX)를 비교한다.
비교해서 그 EAX가 작지 않으면, 즉 크거나 같으면 00444C71로 점프시킨다.
00444C71에는 위와 같이 또 다른 몇 개의 함수들이 있다.
우린 00444C71로 넘어가기 전에 왜 갑자기 EBX+4와 EAX(실행시간)을 비교했는지 생각해봐야 한다.
..간단하게 [EBX+4]의 값이 실행시간이라고 추측할 수 있다.
역시 EAX와 같은 값은 아니다.
EBX+4의 값은 0x00002B70이고 이를 십진수로 변환하면 된다!
'Wargame > CodeEngn.com' 카테고리의 다른 글
Basic RCE L02, L03 (0) | 2020.06.07 |
---|---|
Basic RCE L09 (0) | 2020.06.04 |
Advance RCE L01 (0) | 2020.05.10 |