일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- rev
- CANARY
- toddler
- PMA
- pwnable.kr
- CTF
- writeup
- shellcraft
- Toddler's Bottle
- Reverse
- BOF
- practicalmalwareanalysis
- shellcode
- reversing
- Bug
- Leak
- ASM
- Read
- TUCTF
- Bottle
- Rookiss
- 2018
- picoCTF
- pwn
- format
- string
- FSB
- pwnable
- pico
- anti
- Today
- Total
제리의 블로그
PMA Lab16-02.exe 안티디버깅 본문
Lab16-02.exe
질문
1. 커맨드라인에서 Lab16-02.exe를 실행할 때 어떤 일이 발생하는가?
C:\ProgramData\chocolatey\lib\pmalabs\tools\Practical Malware Analysis Labs\Bina
ryCollection\Chapter_16L>Lab16-02.exe
usage: Lab16-02.exe <4 character password>
2. Lab16-02.exe를 실행할 때 어떤 일이 일어나는지 보고 커맨드라인의 파라미터를 추측해라.
C:\ProgramData\chocolatey\lib\pmalabs\tools\Practical Malware Analysis Labs\Bina
ryCollection\Chapter_16L>Lab16-02.exe p@ss
Incorrect password, Try again.
3. 커맨드라인 패스워드는 무엇인가?
올바른 커맨드라인 패스워드는 bzrr이다.
4. Lab16-02.exe를 IDA Pro에 로드하자. main 함수에서 strncmp는 어디에서 발견했는가?
CreateThread(0, 0, StartAddress, 0, 0, &ThreadId);
Sleep(1000);
v5 = strncmp(argv[1], &byte_408030, 4u);
if ( v5 )
sub_402148(aIncorrectPassw);
else
sub_402148(aYouEnteredTheC);
패스워드를 알아보기 위해서 정적디버깅을 해보았습니다.
.tls:0040123A 에서 strncmp가 사용되었고
byte_408030 의 문자열과 비교하는 것으로 밝혀졌는데요
5. 기본 설정으로 사용하는 OllyDbg에 이 악성코드를 로드하면 어떤 일이 발생하는가?
Terminated 됩니다. main(4011E0)에 BP 해봐도 똑같습니다.
6. Lab16-02.exe의 PE 구조에서 유일한 것은 무엇인가?
main 함수가 위치한 섹션을 보니 .text가 아니었습니다.
바로 .tls 였습니다.
7. 콜백 위치는 어디인가? (힌트: IDA Pro에서 Ctrl+E를 사용해보자)
Name Address
TlsCallback_0 00401060
start 00402179 [main entry]
0x401060이 콜백 위치입니다.
8. 어떤 안티디버깅 기법을 이용해 디버거에서 즉시 종료하게 사용하는가? 어떻게 이 확인을 우회할 수 있는가?
FindWindowA 함수가 악성코드를 종료하는 데 사용됩니다.
.tls:00401060 push ebp
.tls:00401061 mov ebp, esp
.tls:00401063 cmp [ebp+arg_4], 1
.tls:00401067 jnz short loc_401081
.tls:00401069 push 0 ; lpWindowName
.tls:0040106B push offset ClassName ; "OLLYDBG"
.tls:00401070 call ds:FindWindowA
.tls:00401076 test eax, eax
.tls:00401078 jz short loc_401081
.tls:0040107A push 0 ; int
.tls:0040107C call _exit
클래스 이름이 OLLYDBG인 윈도우를 찾으며, 발견하면 프로그램을 종료합니다.
PhantOm 같은 플러그인을 사용해 윈도우 클래스 이름을 변경하거나 0x40107C에 있는 exit 호출을 제거할 수 있습니다.
9. 안티디버깅 기법을 비활성화한 이후 디버거에서 봤던 커맨드라인 패스워드는 무엇인가?
FindWindowA 안티디버깅 기법을 굳이 비활성화지 않고 OllyDbg 대신 IDA로 해봤습니다.
.data:00408030 ; char byte_408030
.data:00408030 byte_408030 db 50h ; DATA XREF: StartAddress+22w
.data:00408030 ; StartAddress+60w ...
.data:00408030 에 하드 브포를 걸고 실행을 합니다.
argc가 1이면 "usage: Lab16-02.exe <4 character password>" 를 출력하고 종료되기 때문에
검증하는 부분을 넘어가기 위해서
파라미터도 아무거나 지정해줍니다.
---------------------------
Warning
---------------------------
Hardware breakpoint at 00408030 has been triggered
---------------------------
OK
---------------------------
그러면 위와 같이 잡히게 됩니다.
.tls:004011D5 retn 4
까지 실행시키면
password 는 '#zrr' 이라고 나옵니다.
10. 커맨드라인에서 동작할 때 디버거에서 패스워드를 발견했는가?
C:\ProgramData\chocolatey\lib\pmalabs\tools\Practical Malware Analysis Labs\Bina
ryCollection\Chapter_16L>Lab16-02.exe #zrr
Incorrect password, Try again.
#zrr 을 넣어봤는데 올바른 패스워드가 아니었습니다.
11. 디버거와 커맨드라인에서 서로 다른 패스워드를 설명할 수 있는 기술은 무엇인가? 그리고 이런 기술을 어떻게 막을 수 있는가?
첫번째 기술: OutputDebugStringA
.tls:0040109B mov bl, byte_40A968
...
.tls:00401111 add byte ptr password+1, bl
byte_40A968 이 패스워드 디코딩 알고리즘에 사용되는 것을 알 수 있는데
이 byte_40A968 은 OutputDebugStringA 함수의 결과에 따라 다른 값이 저장되도록 만들어 놓았습니다.
* OutputDebugStringA 는 디버거에게 문자열을 출력하는 것으로 성공/실패여부를 반환값으로 갖습니다.
.tls:00401035 push offset OutputString ; "b"
.tls:0040103A call ds:OutputDebugStringA
.tls:00401040 call ds:GetLastError
.tls:00401046 cmp eax, [ebp+dwErrCode]
.tls:00401049 jnz short loc_40105A
.tls:0040104B mov cl, byte_40A968
.tls:00401051 add cl, 1
.tls:00401054 mov byte_40A968, cl
.tls:0040103A 를 보면 OutputDebugStringA 가 사용되었습니다.
디버거에게 메시지가 전달된 모습을 확인할 수 있습니다.
OutputDebugString 부분은 0x401051의 add 연산을 못하도록 바이너리 패치하여 제거해줍니다.
두번째 기술: BeingDebugged 플래그
.tls:0040112B mov ebx, large fs:30h
...
.tls:0040118B mov bl, [ebx+2]
...
.tls:004011A2 add byte ptr password+2, bl
디버깅 중이면 BeingDebugged 플래그 1일텐데
그 1을 더하는 3줄짜리 어셈코드가 서로 떨어져있었다.
이런것도 난독화라면 난독화일 수 있겠죠 ㅎㅎ;;
번외
안티디버깅이 적용되어있으므로
정적디버깅만으로 프로그램을 간단히 분석하고
바이너리 패치로 키값을 뽑아내는 방법도 해보았습니다.
v5 = strncmp(argv[1], &byte_408030, 4u);
if ( v5 )
sub_402148(&byte_408030);
else
sub_402148(aYouEnteredTheC);
main 함수에서
원래 "Incorrect password, Try again" 를 출력하는 부분을
byte_408030을 출력하도록 패치하면
대신 실패 문구 대신 패스워드를 출력할 것입니다.
C:\ProgramData\chocolatey\lib\pmalabs\tools\Practical Malware Analysis Labs\Bina
ryCollection\Chapter_16L>Lab16-02.exe abcd
bzrrp@ss
그랬더니 "bzrr" 가 패스워드임을 알아냈습니다.
패스워드가 맞는지 다시한번 원본파일에 검증을 해봅니다.
C:\ProgramData\chocolatey\lib\pmalabs\tools\Practical Malware Analysis Labs\Bina
ryCollection\Chapter_16L>Lab16-02.exe bzrr
You entered the correct password!
성공입니다.
책에는 byrr 이 패스워드라고 적혀있었는데
C:\ProgramData\chocolatey\lib\pmalabs\tools\Practical Malware Analysis Labs\Bina
ryCollection\Chapter_16L>Lab16-02.exe byrr
Incorrect password, Try again.
저는 뭐가 잘못된거일까요..