-
리버싱 예제) CodeEngn Basic L16리버싱/리버싱스러운것 2024. 12. 26. 13:41
코드엔진 basic 16번을 풀어보도록 하겠다.
Name과 Password를 입력하고 맞는지 체크하는 흔한 유형이다
보통 이런류는 입력한 Name에 따라 시리얼 값이 달라지는 경우가 대부분이다(사실 100%임)
Name 값이 CodeEngn 일때의 Password 값을 구해야 하는데...
일단 정적 분석 도구인 기드라를 통해 한번 열어봤다
처음 로딩하면 메인함수로 갖다 주는데 뭐가 엄청많다.
아까 틀린 패스워드를 입력하면 Wrong Password 문구가 출력되던데 그 부분이 어딘지 찾는다.
핵심 분기는 저기다, local_44와 local_40의 값이 같은지의 여부에 따라 분기가 나뉘는데 한번 x32dbg로 돌려봄
아까본 Wrong password 문구가 출력되는 부분으로 ㄱㄱ
그 위로 가보면 아까의 if문에 해당하는 cmp 명령어가 한 줄 있다.
비교 후 밑의 jne 명령어를 통해 password 값이 맞지 않으면 wrong 쪽으로 배달시키는 구문이라고 쉽게 예측이 가능하다
나는 이 문제를 2개의 방법으로 풀었는데 그 중 첫 번째는 가장 간단한 방법이다.
우선 Name 값에 CodeEngn을 입력한다. 비번은 그냥 아무거나 쳐라이~
F8을 누르며 오다가 아까 본 cmp 문에서 멈춰준다. eax 값과 EBP-3C 값이 같은지 비교하는 것 인데
EBP-3C에 무슨 값이 있는지 보자, 참고로 현재 EBP 값이 0070FF28인데 여기서 3C를 빼준거니
0070FEEC에 있는 값을 보면 된다. 참고로 dword니 4바이트 읽어온다.
EBP-3C에서 E4C60D97 값을 가져오는 것을 볼 수 있다. 우리가 입력한 비밀번호는 HEX값으로 저장되니,
저 값의 10진수 값이 CodeEngn의 시리얼 값이다.
E4C60D97을 10진수로 바꾸면 3838184855 라는 값이 나온다. 이 값을 한번 넣어보자
당연하게도 맞는 값이라고 나온다. 여기까지가 첫 번째 풀이 방법이다.
느끼는거지만 해킹 예제 풀면서 정답은 없는 것 같다. 위 방법 말고도 코드를 패치한다던가, 플래그 값을 바꿔서 넘어간다던가
그런 방법들이 있는데, 이번에는 이 문제의 본질인 가장 정석적인 방법 시리얼 값이 만들어지는 과정을 한번 알아보도록 하겠다.
다시 기드라의 메인함수로 돌아간다. Enter Your Name 후에 local_3c에 사용자의 입력을 받는 부분이 보인다.
어떻게 알았냐고?? gpt한테 물어보면 된다.
보기 쉽게 local_3c를 my_name 이라는 예쁜 이름으로 바꿔준다.
여기랑 아까 위에 사이에 자잘한 뭐 있는데 별로 안중요해서 보여서 뺐다.
코드로보면 정말 쉬울 거 같은데 디컴파일된 결과를 보면 뭔 개소린지 하나도 모른다.
gpt의 힘을 이용하면 편리하지만, 직접 읽어보면서 유추하거나 맞춰보며 가는게 실력 향상에 더 도움이 될 거라고 생각한다.
위에 읽어보면 뭐시기가 엄청 많은데 결과만 말하면 ivar3에는 60이라는 값이 들어간다.
다시 x32dbg를 통해 봐보자
맨처음에 edx에 8이 들어간다. 그리고 eax에 edx의 값(8)을 넣어준다. 우리는 아까 length 함수를 통해 입력한 name의 길이를 가져오는 걸 보았다.
고로 지금 이 8은 CodeEngn의 글자수 8이라는 것을 알 수 있다. 이 명령어들 위에 함수가 있어서 이게 뭔가 할 수 있는데...
아마 글자수만큼 반복해서 숫자를 +1 한 뒤 반환하는(length 함수) 그런거 일 듯 별로 중요한게 아니다.
연산 과정을 간략하게 표현하면
1. edx=8의 값을 eax에 넣음
2. eax = eax + eax = 0x8 + 0x8 = 10
3. eax = eax + edx = 0x10 + 0x8 고로 eax는 0x18가 된다
4. shl eax,2 0x18을 왼쪽으로 쉬프트 연산 2만큼 진행 결과는 60이된다
다시 기드라를 봐보자
local_24에는 입력한 name의 길이 8이 들어간다고 했다
근데 기드라에서 본 ivar3에는 local_24 * 0xC = 0x8(8) * 0xC(10진수로 12) = 0x60 결과만 놓고 보면 동일 하다. 왜일까?
이것은 위에서 수행한 연산들과 0xC를 곱하는게 결과적으로 같은 내용이기 떄문이다
위 내용을 천천히 분석해보자
name의 길이에 같은 값을 더함 = name * 2
거기에 원래 name 값을 더함 = name길이 * 3
거기에 왼쪽으로 쉬프트 연산 2만큼 이동 = 4를 곱함
결과만 놓고보면 (name의 길이 * 3) * 4 따라서 name의 길이 * 12(0xC)를 곱하는 것과 같은 결과가 나오게 되는 것이다.
고로 결과로 나온 0x60 값이 ivar3에 들어간다.
그 후 ivar3을 3제곱 한 뒤 0x17을 더 해준다 이 과정은 x32dbg에서도 동일하게 보인다
그 다음에는 마지막으로 대뜸 비밀번호 입력 후 그 위 값에 0xace81을 곱하는데 최종적으로 이것이 우리가 원하던 CodeEngn의 시리얼 값이 된다
최종 계산 값 : 0x91E4C60D97
이걸 메모리에 저장하면 이런식으로 된다그리고 dword ptr ss:[ebp-3C] 는 저 주소에서 하위 4바이트를 읽어오는데
해당 프로그램은 리틀엔디안 방식을 사용하고 있으므로 실제로 불러오는 값은 E4C60D97 이다.
위에 넣지는 않았지만 비밀번호 입력 후 이 값이 HEX로 환산되어 저장되므로,
이 값을 10진수로 표현한 것이 우리가 입력해야할 password인 것이다.
끝.
'리버싱 > 리버싱스러운것' 카테고리의 다른 글
함수호출규약 (0) 2023.06.18 Basic RCE L14, KeyCrackmMe - #2 (0) 2023.06.09 Basic RCE L10 (0) 2023.06.06 Notepad_upx.exe 분석 (1) 2023.06.01 실행압축 - 194p (0) 2023.05.30