[TrendMicro CTF 2017] Writeup - Reversing 400 ScreenKeyPad
주어진 바이너리를 실행하면 이런 폼이 뜬다.
델파이로 개발되어있는데 한때 나도 델파이 개발을 한 적이 있어 친근했다.
먼저 알아야 할 것은 VMProtect로 패킹되어 있는데다가 Virtualization이 있어 버튼 클릭 이벤트와 FormActivate 코드 내부는 분석 할 수가 없다. 뭔가 꼼수를 요구하는 것 같다.
시간이 지날때마다 버튼의 배치가 바뀐다.
저 progress 가 41216 까지 도달하면 될 것 같아 시간을 패치해서 끝까지 올려보았지만 아무일도 없었다.
멘붕에 빠지던 중 종료 1시간전에 팀원이 마우스 좌표가 바뀌는 대로 Hex로 보면 7z이 나온다고 하였다. 결국 대회 끝나고 밥먹고 와서 풀었다 ㅠ
다시 확인해 보았지만 내 가상머신에서는 마우스가 이동되지 않아 다른 컴퓨터로 확인해 본 결과 마우스가 이동되어 버튼에 올려지는 것을 알 수 있었다.
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. 버튼 좌표는 어떻게 얻고 -> 해결
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. 버튼 좌표는 어떻게 얻고
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. 버튼 좌표는 어떻게 얻고
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 |