문제를 다운받고 실행하면 Nope 이 나온다.
ELF64 파일인데, 아이다로 열어보면 사용되는함수밖에 나오지 않는다.
int __cdecl __libc_start_main( int (__cdecl *main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void *stack_end)
__libc_start_main 함수이다. 이 함수에서 main 함수를 호출하는데,
동적분석으로 인자로 받는 main함수의 위치를 알아보자
main 함수는 0x555555554a3a 에 있다고한다.
[ main ]
지금부터 메인함수를 나눠서 설명해드릴께요
0x555555554a42: mov DWORD PTR [rbp-0x24],edi
0x555555554a45: mov QWORD PTR [rbp-0x30],rsi
- rbp-0x24 : argc ( main함수 인자개수 )
- rbp-0x30 : argv ( main함수 인자 )
0x555555554a58: lea rdi,[rip+0x151] # "team_name"
0x555555554a5f: call 0x5555555546a0 <getenv@plt>
0x555555554a64: mov QWORD PTR [rbp-0x10],rax
0x555555554a68: cmp QWORD PTR [rbp-0x10],0x0
0x555555554a6d: je 0x555555554af3
0x555555554a73: mov rax,QWORD PTR [rbp-0x10]
0x555555554a77: mov edx,0x4
0x555555554a7c: lea rsi,[rip+0x137] # "bi0s"
0x555555554a83: mov rdi,rax
0x555555554a86: call 0x5555555546b0 <strncmp@plt>
0x555555554a8b: test eax,eax
0x555555554a8d: jne 0x555555554af3
team_name 이란 환경변수값을 가져와서 있는지없는지 검사후, 그 값을 bi0s 와 비교 (조건 불만족시 종료 )
0x555555554a8f: cmp DWORD PTR [rbp-0x24],0x2
0x555555554a93: je 0x555555554aa8
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x555555554aa8: mov rax,QWORD PTR [rbp-0x30]
0x555555554aac: add rax,0x8
0x555555554ab0: mov rdx,QWORD PTR [rax]
0x555555554ab3: mov rax,QWORD PTR [rbp-0x10]
0x555555554ab7: mov rsi,rdx
0x555555554aba: mov rdi,rax
0x555555554abd: call 0x55555555487c
main 함수의 인자가 두개이면, 0x55555555487c 호출,
인자 : argv[1](main함수 두번째인자), "bi0s"
0x555555554ac2: mov DWORD PTR [rbp-0x14],eax
0x555555554ac5: cmp DWORD PTR [rbp-0x14],0x1
0x555555554ac9: jne 0x555555554ae0
0x555555554acb: mov rax,QWORD PTR [rbp-0x30]
0x555555554acf: add rax,0x8
0x555555554ad3: mov rax,QWORD PTR [rax]
0x555555554ad6: mov rdi,rax
0x555555554ad9: call 0x555555554830
0x555555554ade: jmp 0x555555554b04
0x55555555487c 의 리턴값이 1이면, 0x55555554830 호출하고 종료
[ 0x55555554830 ]
암호화된 문자열 출력함수
HackCTF{ %s }
[ 0x55555555487c ]
문자열 암호화 후 비교함수
0x555555554885: mov QWORD PTR [rbp-0x68],rdi
0x555555554889: mov QWORD PTR [rbp-0x70],rsi
0x55555555488d: mov DWORD PTR [rbp-0x18],0x0
0x555555554894: mov DWORD PTR [rbp-0x1c],0x0
0x55555555489b: movabs rax,0x3931383137313631
0x5555555548a5: mov QWORD PTR [rbp-0x40],rax
0x5555555548a9: movabs rax,0x3731363138333632
0x5555555548b3: mov QWORD PTR [rbp-0x38],rax
0x5555555548b7: mov DWORD PTR [rbp-0x30],0x31393139
0x5555555548be: mov WORD PTR [rbp-0x2c],0x3439
0x5555555548c4: mov BYTE PTR [rbp-0x2a],0x0
- rbp-0x68 : "bi0s"
- rbp-0x70 : argv[1] ( 입력한 문자열 )
- rbp-0x40 : "1617181926381617919194"
0x5555555548c8: mov rax,QWORD PTR [rbp-0x70]
0x5555555548cc: mov rdi,rax
0x5555555548cf: call 0x5555555546c0 <strlen@plt>
0x5555555548d4: cmp rax,0x16
0x5555555548d8: je 0x5555555548e4
입력한 문자열 길이가 0x16 (22) 이여야한다.
0x5555555548e4: mov DWORD PTR [rbp-0x14],0x0
0x5555555548eb: jmp 0x555555554907
0x5555555548ed: mov eax,DWORD PTR [rbp-0x14]
0x5555555548f0: movsxd rdx,eax
0x5555555548f3: mov rax,QWORD PTR [rbp-0x68]
0x5555555548f7: add rax,rdx
0x5555555548fa: movzx eax,BYTE PTR [rax]
0x5555555548fd: movsx eax,al
0x555555554900: add DWORD PTR [rbp-0x18],eax
0x555555554903: add DWORD PTR [rbp-0x14],0x1
0x555555554907: mov eax,DWORD PTR [rbp-0x14]
0x55555555490a: movsxd rbx,eax
0x55555555490d: mov rax,QWORD PTR [rbp-0x68]
0x555555554911: mov rdi,rax
0x555555554914: call 0x5555555546c0 <strlen@plt>
0x555555554919: cmp rbx,rax
0x55555555491c: jb 0x5555555548ed
while( i < 4 ) {
[ rbp-0x18 ] += [ rbp-0x68 ][ i ] # "bi0s"
}
rbp-0x68 = 0x16e (366)
0x55555555492d: mov ecx,DWORD PTR [rbp-0x18]
0x555555554930: mov edx,0x88888889
0x555555554935: mov eax,ecx
0x555555554937: imul edx
0x555555554939: lea eax,[rdx+rcx*1]
0x55555555493c: sar eax,0x4
0x55555555493f: mov edx,eax
0x555555554941: mov eax,ecx
0x555555554943: sar eax,0x1f
0x555555554946: sub edx,eax
0x555555554948: mov eax,edx
0x55555555494a: mov DWORD PTR [rbp-0x18],eax
[rbp-0x18] = (0x16e * 0x88888889 의 상위 8바이트) >> 4 - 0x16e >> 0x1F (31)
[rbp-0x18] = 0xC (12)
0x55555555494d: cmp DWORD PTR [rbp-0x1c],0x16
0x555555554951: je 0x5555555549b9
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x55555555497d: mov eax,DWORD PTR [rbp-0x1c]
0x555555554980: movsxd rdx,eax
0x555555554983: mov rax,QWORD PTR [rbp-0x70]
0x555555554987: add rax,rdx
0x55555555498a: movzx eax,BYTE PTR [rax]
0x55555555498d: sub eax,0x4
0x555555554990: mov edx,eax
0x555555554992: mov eax,DWORD PTR [rbp-0x1c]
0x555555554995: cdqe
0x555555554997: mov BYTE PTR [rbp+rax*1-0x60],dl `다음코드는 99b`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x555555554953: mov eax,DWORD PTR [rbp-0x1c]
0x555555554956: and eax,0x1
0x555555554959: test eax,eax
0x55555555495b: jne 0x55555555497d
0x55555555495d: mov eax,DWORD PTR [rbp-0x1c]
0x555555554960: movsxd rdx,eax
0x555555554963: mov rax,QWORD PTR [rbp-0x70]
0x555555554967: add rax,rdx
0x55555555496a: movzx eax,BYTE PTR [rax]
0x55555555496d: add eax,0x4
0x555555554970: mov edx,eax
0x555555554972: mov eax,DWORD PTR [rbp-0x1c]
0x555555554975: cdqe
0x555555554977: mov BYTE PTR [rbp+rax*1-0x60],dl
0x55555555497b: jmp 0x55555555499b
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x55555555499b: mov eax,DWORD PTR [rbp-0x1c]
0x55555555499e: cdqe
0x5555555549a0: movzx edx,BYTE PTR [rbp+rax*1-0x60]
0x5555555549a5: mov eax,DWORD PTR [rbp-0x18]
0x5555555549a8: xor edx,eax
0x5555555549aa: mov eax,DWORD PTR [rbp-0x1c]
0x5555555549ad: cdqe
0x5555555549af: mov BYTE PTR [rbp+rax*1-0x60],dl
0x5555555549b3: add DWORD PTR [rbp-0x1c],0x1
0x5555555549b7: jmp 0x55555555494d
while ( i < 0x16 (22) ) {
if (i%2==1)
[rbp-0x60][ i ] = [ rbp-0x70 ][ i ] - 4
else
[rbp-0x60][ i ] = [ rbp-0x70 ][ i ] + 4 #짝수홀수 구분, 짝수는 +4, 홀수는 -4
[rbp-0x60][ i ] = [rbp-0x60][ i ] ^ 0xC
i++
}
0x5555555549c9: lea rax,[rbp-0x60]
0x5555555549cd: mov rdi,rax
0x5555555549d0: call 0x5555555546c0 <strlen@plt>
0x5555555549d5: sub eax,0x1
0x5555555549d8: mov DWORD PTR [rbp-0x14],eax
0x5555555549db: jmp 0x555555554a19
0x5555555549dd: lea rax,[rbp-0x60]
0x5555555549e1: mov rdi,rax
0x5555555549e4: call 0x5555555546c0 <strlen@plt>
0x5555555549e9: mov rdx,rax
0x5555555549ec: mov eax,DWORD PTR [rbp-0x14]
0x5555555549ef: cdqe
0x5555555549f1: sub rdx,rax
0x5555555549f4: mov rax,rdx
0x5555555549f7: sub rax,0x1
0x5555555549fb: movzx edx,BYTE PTR [rbp+rax*1-0x60]
0x555555554a00: mov eax,DWORD PTR [rbp-0x14]
0x555555554a03: cdqe
0x555555554a05: movzx eax,BYTE PTR [rbp+rax*1-0x40]
0x555555554a0a: cmp dl,al
0x555555554a0c: je 0x555555554a15
0x555555554a0e: mov eax,0x0
0x555555554a13: jmp 0x555555554a33
0x555555554a15: sub DWORD PTR [rbp-0x14],0x1
0x555555554a19: cmp DWORD PTR [rbp-0x14],0x0
0x555555554a1d: jns 0x5555555549dd
0x555555554a1f: mov DWORD PTR [rbp-0x24],0x0
0x555555554a26: cmp DWORD PTR [rbp-0x24],0x1
0x555555554a2a: jne 0x555555554a2e
i=0x16
t = 0x15
while( i>0 ) {
if ( [rbp-0x60][ i-t ] != [rbp-0x40][ t ] ) #문자열을 역순으로 가져온다
#종료
t--
}
[ 최종 암호화루틴 ]
[rbp-0x40] : "1617181926381617919194"
[rbp-0x18] = 0xC
[rbp-0x68] = 0x16e
i=0
while ( i < 0x16 (22) ) {
if (i%2==1)
[rbp-0x60][ i ] = [ rbp-0x70 ][ i ] - 4
else
[rbp-0x60][ i ] = [ rbp-0x70 ][ i ] + 4
[rbp-0x60][ i ] = [rbp-0x60][ i ] ^ 0xC
i++
}
i=0x16
t = 0x15
while( i>0 ) {
if ( [rbp-0x60][ i-t ] != [rbp-0x40][ t ] )
break
t--
}
헨드레이하느라 힘들었다. 이제 이걸 이용해 복호화하는 코드로 옮겨보자
[ python ]
[rbp-0x40] 에서 [rbp-2B] ~ [rbp-0x40] 이렇게 역순으로 가져오기때문에,
역순으로 변수에 저장한다.
encoded="1617181926381617919194"
encoded=encoded[::-1]
var18=0xC
var68=0x16e
s=""
for i in range(0,0x16):
t=ord(encoded[i])^var18
if i%2==1:
t+=4
else :
t-=4
s+=chr(t)
print("HackCTF{"+s+"}")
flag 가 의미없는 숫자로 나오길래 망했다 생각했지만, FLAG 였다.
[배운점]
handray 와 동적분석