본문 바로가기

Reversing/DreamHack

[DreamHack_wargame] rev_basic_5번

문제 : 이 문제는 사용자에게 문자열 입력을 받아 정해진 방법으로 입력 값을 검증하여 correct 또는 wrong을 출력하는 프로그램이 주어집니다. 해당 바이너리를 분석하여 correct를 출력하는 입력 값을 찾으세요.

 

< main 함수 >

 

: eax와 eax를 비교하여, 두 값이 같으면(ZF=1, eax=0) “wrong”으로 점프

따라서, correct가 출력되기 위해서는 eax가 0이 아니어야 하고,

위의 두번째 그림에서 오른쪽 아래로 진행되어야 함.

eax 값을 비교하는 sub_7FF688611000 함수 내부를 살펴보자

 

 

 

< sub_7FF688611000 >

 

[ Flow ]

1.    eax가 0이 되어서는 안되므로, 7번 블록으로 진행되면 안됨 (xor으로 인해 eax가 0이 됨)

2.    “2 -> 4 -> 5 -> 6”이 반복되다가, 마지막에 “3 -> 8”으로 진행하고 마무리 됨

3.    rcx = input / [rsp] = count

 

 

[1번 블록]

1.    | mov qword ptr ss:[rsp+8],rcx            |

         : [rsp+8] = rcx

2.    | sub rsp,18                              |

  : 스택 증가 (스택 증가로, 위의 rcx는 [rsp+0x20]에 담김)

3.    | mov dword ptr ss:[rsp],0                |

         : [rsp] = 0

4.    | jmp chall5.7FF68861101A                 |

: 2번 블록으로 점프

 

[2번 블록]

1.    | movsxd rax,dword ptr ss:[rsp]           |

         : rax = [rsp] = 0

2.    | cmp rax,18                              |

         : rax와 0x18(24)비교

3.    | jae chall5.7FF68861105D                 |

: jea( rax >= 0x18이면 점프) /

 그러나 점프하면 안되므로, rax<0x18(24)이어야 하고,

0~23번까지 24회 비교하는 것을 알 수 있음.

 

[4번 블록]

1.    | movsxd rax,dword ptr ss:[rsp]           |

          : rax = [rsp] (rax=0) <count>

2.    | mov rcx,qword ptr ss:[rsp+20]           |

          : rcx = [rsp+20]= <input>

3.    | movzx eax,byte ptr ds:[rcx+rax]         |

          : eax = [rcx+rax] (eax에 input의 count번째 글자 저장)

4.    | mov ecx,dword ptr ss:[rsp]              |

           : ecx = [rsp] = <count>

5.    | inc ecx                                 |

           : ecx = ecx+1 = <count+1>

6.    | movsxd rcx,ecx                          |

           : rcx = ecx = <count+1>

7.    | mov rdx,qword ptr ss:[rsp+20]           |

           : rdx = [rsp+20] = <input>

8.    | movzx ecx,byte ptr ds:[rdx+rcx]         |

           : ecx = [rdx+rcx] (eax에 input의 count+1번째 글자 저장)

9.    | add eax,ecx                             |

           : eax = input(count) + input(count+1)

10. | movsxd rcx,dword ptr ss:[rsp]           |

           : rcx = [rsp] = <count>

11. | lea rdx,qword ptr ds:[7FF688613000]     |

           : rdx에 [7FF688613000] 주소값 저장

12. | movzx ecx,byte ptr ds:[rdx+rcx]         |

           : ecx = [rdx+rcx] ([7FF688613000]에 저장된 값 중 count번째 글자 저장)

13. | cmp eax,ecx                             |

           : eax와 ecx 비교

            Input(count)+input(count+1) 과 rdx(count) 비교

14. | je chall5.7FF68861105B                  |

           : 같으면 5번 블록으로 점프

 

[5,6번 블록]

1.    | jmp chall5.7FF688611012                 |

          : 6번 블록으로 진행

2.    | mov eax,dword ptr ss:[rsp]              |

          : eax = [rsp] <count>

3.    | inc eax                                 |

          : eax = eax+1 <count+1>

4.    | mov dword ptr ss:[rsp],eax              |

          : [rsp] = eax

 

 

 

< [7FF688613000] >

해당 위치로 덤프해서 따라가면 위의 그림과 같은 값들이 담겨져 있는 것을 알 수 있음.

그러나 위의 함수에서 본 것과 같이 0-23번, 총 24번을 비교해야 하는데,

위의 그림에서는 4c까지 23개임. 따라서 00까지 포함시켜 역연산을 진행하여야 함.

 

AD, D8, CB, CB, 9D, 97, CB, C4, 92, A1, D2, D7, D2, D6, A8, A5,

DC, C7, AD, A3, A1, 98, 4C, 00

 

 

< 역연산 >

주소값 안에 있는 아스키 코드들을 숫자로 변환하면 173, 216, 203, …, 152, 76 이 된다.

위의 cmp에 따라 ecx에 들어있는 값이 위의 숫자들에 해당하고, 이를 거꾸로 하기 위해서는 리스트에 위의 문자들을 거꾸로 넣어주고 76을 변수로 지정하여 하나씩 빼주는 방식으로 입력값을 찾을 수 있다.

또한 76은 리스트에 넣지 않고 코도를 진행했기 때문에, 출력값의 천번째에 76의 아스키 코드인 L을 덧 붙여서 거꾸로 돌려주면 All_l1fe_3nds_w1th_NULL이 된다.

 

 

정답 : All_l1fe_3nds_w1th_NULL

'Reversing > DreamHack' 카테고리의 다른 글

[DreamHack_Wargame] rev_basic_7번  (0) 2021.05.24
[DreamHack_Wargame] rev_basic_6번  (0) 2021.05.15
[DreamHack_wargame] rev_basic_4번  (0) 2021.04.13
[DreamHack_wargame] rev_basic_3번  (0) 2021.04.13
[DreamHack_wargame] rev_basic_2번  (0) 2021.04.12