[TrendMicro CTF 2017] Writeup - Reversing 400 ScreenKeyPad

Posted by push0ebp
2017. 6. 26. 00:12 Hacking/CTF

주어진 바이너리를 실행하면 이런 폼이 뜬다.

델파이로 개발되어있는데 한때 나도 델파이 개발을 한 적이 있어 친근했다.


먼저 알아야 할 것은 VMProtect로 패킹되어 있는데다가 Virtualization이 있어 버튼 클릭 이벤트와 FormActivate 코드 내부는 분석 할 수가 없다. 뭔가 꼼수를 요구하는 것 같다.


시간이 지날때마다 버튼의 배치가 바뀐다.

저 progress 가 41216 까지 도달하면 될 것 같아 시간을 패치해서 끝까지 올려보았지만 아무일도 없었다.

멘붕에 빠지던 중 종료 1시간전에 팀원이 마우스 좌표가 바뀌는 대로 Hex로 보면 7z이 나온다고 하였다. 결국 대회 끝나고 밥먹고 와서 풀었다 ㅠ

다시 확인해 보았지만 내 가상머신에서는 마우스가 이동되지 않아 다른 컴퓨터로 확인해 본 결과 마우스가 이동되어 버튼에 올려지는 것을 알 수 있었다.


이제 이 마우스가 가리키는 버튼의 Caption대로 어떻게 데이터를 추출 할 것인지가 문제인데 나는. 코드를 패치 하기로 하였다.

DLL을 인젝션 하고 싶었지만 x64 process 라 후킹이 쉽지 않기 때문에 코드를 패치 하기로 결정 하였다.


패치를 한다고는 했는데


1. 어딜 해야하며

2. 좌표는 어떻게 얻고

3. 그 많은 버튼 중에 어떤 버튼을 가르키고 있는지

4. 캡션의 내용은 무엇인지

5. 그 많은 데이터를 언제 다 추출 할지

어떻게 알까?


마우스 좌표를 이동한다면 흔히 mouse_event나 SetCursorPos 를 쓸텐데 디버깅 결과 mouse_event는 Access하지 않았고 SetCursorPos(SetPhysicalCursorPos)를 사용 하고 있었다.

SetCursorPos 의 원형은 이렇다

int SetCursorPos(int x, int y)

rcx에 x좌표 rdx의 y좌표 를 인자로 전달해 주어야 한다.


마우스를 움직일때마다 접근을 하고 좌표도 알 수 있으니 이곳을 Hook 하면 될 것 같다.


1. 어딜 패치 해야하며 -> 해결
2. 그 많은 버튼 중에 어떤 버튼을 가르키고 있는지

3. 버튼 좌표는 어떻게 얻고

4. 버튼의 내용은 무엇인지


008E1D60에서 Button Object의 Table 을 발견했다.



버튼은 총 16개로 순서대로 16개가 enumerate 되어 있어 버튼의 Caption은 index로 알아낼수 있다.


1. 어딜 패치 해야하며
2. 그 많은 버튼 중에 어떤 버튼을 가르키고 있는지

3. 버튼 좌표는 어떻게 얻고

4. 버튼의 내용은 무엇인지 -> 해결

5. 그 많은 데이터를 언제 다 추출 할지




이 중 첫번째 Object를 살펴 보았다. 그런데 빨간 부분을 보니 버튼의 Left, Top property 즉 x, y 좌표가 들어 있었다. 

Offset 은 +0x80 : x +0x84 : y 로 나타낼 수 있다.


1. 어딜 패치 해야하며
2. 그 많은 버튼 중에 어떤 버튼을 가르키고 있는지

3. 버튼 좌표는 어떻게 얻고 -> 해결

4. 버튼의 내용은 무엇인지

5. 그 많은 데이터를 언제 다 추출 할지


필요한 정보는 다 구했다. 이제 마우스가 버튼을 가르키고 있는지 체크만 하면 된다.

마우스 x 좌표 - 버튼 Left < 버튼 Width

마우스 y 좌표 - 버튼 Top < 버튼 Height

라면 버튼 위에 마우스를 올려놓은 상태 일 것이다.

하지만 마우스 x 좌표는 화면 상의 좌표일뿐 바이너리 폼상의 좌표가 아니다.

절대 좌표를 상대 좌표로 변환해 주어야 한다.


(마우스 x 좌표 - 폼 client x 좌표) - 버튼 Left < 버튼 Width

(마우스 y 좌표 - 폼 client y 좌표) - 버튼 Top < 버튼 Height


이제 저 Button Table 로 모든 버튼의 left, top을 체크하여 무슨 버튼 위에 마우스를 올릴 것인지 알아내기로 한다.


1. 어딜 패치 해야하며
2. 그 많은 버튼 중에 어떤 버튼을 가르키고 있는지 -> 해결

3. 버튼 좌표는 어떻게 얻고

4. 버튼의 내용은 무엇인지

5. 그 많은 데이터를 언제 다 추출 할지


이제 후킹 코드만 작성 하면 된다.

나는 Cheat Engine을 이용하여 Script 를 작성했다.


후킹한 모습.


alloc(newmem,2048,USER32.SetCursorPos)

globalalloc(z,412200)
alloc(z_i,4)
label(returnhere)
label(originalcode)
label(exit)
label(end)
label(loop)
label(loop_end)
label(end)
z_i:
dd 0

newmem: //this is allocated memory, you have read,write,execute access
//place your code here
push rdi
push rsi
push rbx //count
push rcx
push rdx
push r8 //btn left
push r9 //btn top
push r10
push r11
sub rcx, #112 //****form client x coord abs -> rel
sub rdx, #135 //****form client y coord abs -> rel
mov rbx, 0
mov rsi, 008E1D60 //button table start
loop:
mov rdi, [rsi] //get button object
mov r8, dword ptr [rdi+80] //left
and r8, ffff
mov r9, dword ptr [rdi+84] //top
and r9, ffff
mov r10, rcx
sub r10, r8 //x offset
cmp r10, #25
jnbe loop_end
mov r11, rdx
sub r11, r9 //y offset
cmp r11, #25
jnbe loop_end
mov rcx, z
mov rdx, [z_i]
add rcx, rdx
mov byte ptr [rcx], bl
add [z_i], 1
jmp end
loop_end:
add rbx, 1
add rsi, 8
cmp rsi,008E1DE0 //button table end
jne loop
end:
pop r11
pop r10
pop r9
pop r8
pop rdx
pop rcx
pop rbx
pop rsi
pop rdi
originalcode:
movsxd  rdx,edx
mov r8d,00000093

exit:
jmp returnhere

USER32.SetCursorPos:
jmp newmem
nop
nop
nop
nop
returnhere:


sub rcx, #112 //****form client x coord abs -> rel
sub rdx, #135 //****form client y coord abs -> rel

이 부분은 상대좌표로 변환하는 부분이니 실행할 때마다 항상 수정해 주어야한다.


데이터 추출은 됐지만 속도가 너무 느리다.

KERNELBASE.SleepEx를 호출 하는데 가볍게 ret으로 패치해주면 빨라진다.


1. 어딜 패치 해야하며
2. 그 많은 버튼 중에 어떤 버튼을 가르키고 있는지

3. 버튼 좌표는 어떻게 얻고

4. 버튼의 내용은 무엇인지

5. 그 많은 데이터를 언제 다 추출 할지 -> 해결


실행하고 기다리면


이렇게 데이터가 추출되어 있다.

37   7A BC AF 27    7z ....


압축을 풀면 stub.exe 가 나오는데 간단한 xor ror 연산이니 이 부분은 생략




**추가

Offensive 200

분석하기 귀찮아서 패치로 풀었는데 스크립트 첨부. 패치하고 기다리면 flag.txt가 알아서 생성된다.


alloc(newmem1,2048)
label(returnhere1)
label(originalcode1)
label(exit1)

newmem1: //this is allocated memory, you have read,write,execute access
//place your code here
mov ebx,[00403009]
test ebx,ebx
jne originalcode1
jmp 00401030
originalcode1:
cmp ebx, [x]
jg 00401030
exit1:
jmp returnhere1

"cracktheflag.exe"+101E:
jmp newmem1
nop
returnhere1:


alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)

globalalloc(x,4)
x:
dd #100000



newmem: //this is allocated memory, you have read,write,execute access
//place your code here
mov [403005], 0
push #10
push 0040301B
push [x]
call msvcrt.itoa
add esp, c
mov eax, [x]
add eax,1
or eax, 1
mov [x], eax
originalcode:
push 0040301B

exit:
jmp returnhere

"cracktheflag.exe"+1071:
jmp newmem
returnhere:

00401195:
jmp 00401071


'Hacking > CTF' 카테고리의 다른 글

[Plaid CTF 2018] Wait Wait... Don't Shell Me  (0) 2018.05.07
2016 디미고 KDMHS CTF  (0) 2016.05.25
세종대 SSG CTF 2016 write up  (1) 2016.04.06
Codegate 2016 Junior Write up  (0) 2016.04.04
inc0gnito 2015 Write up  (0) 2015.08.25