기드라 이용 방법인데 ida를 사용했다 헤헤
프로그램 파일을 받아 디컴파일러하면 이런 소스코드가 뜬다
// positive sp value has been detected, the output may be wrong!
void __fastcall __noreturn start(__int64 a1, __int64 a2, int a3)
{
__int64 v3; // rax
int v4; // esi
__int64 v5; // [rsp-8h] [rbp-8h] BYREF
_UNKNOWN *retaddr; // [rsp+0h] [rbp+0h] BYREF
v4 = v5;
v5 = v3;
sub_402E10((unsigned int)sub_401AD5, v4, (unsigned int)&retaddr, 0, 0, a3, (__int64)&v5);
__halt();
}
이 코드는 C 언어로 작성된 함수로, 특정 작업을 수행한 후 프로그램을 중단하는 역할을 합니다. 주요 부분을 분석하면 다음과 같은 흐름과 특징을 이해할 수 있습니다.
1. 함수의 시그니처
void __fastcall __noreturn start(__int64 a1, __int64 a2, int a3)
- __fastcall:
- 함수가 인자를 레지스터를 통해 전달받는 호출 규약을 의미합니다. 보통 첫 번째와 두 번째 정수형 인자(a1, a2)는 RCX와 RDX 레지스터를 사용합니다. 세 번째 인자(a3)는 R8에 전달됩니다.
- __noreturn:
- 함수가 종료되지 않고 프로그램을 멈추거나 종료될 것임을 의미합니다. (__halt() 때문에 해당 속성이 붙습니다.)
2. 변수 선언
__int64 v3; // rax 레지스터에서 가져오는 64비트 값 (초기화되지 않음)
int v4; // esi 레지스터에서 사용되는 32비트 값
__int64 v5; // 64비트 크기의 스택 변수, 포인터로도 사용 가능
_UNKNOWN *retaddr; // 반환 주소를 저장하는 포인터
- v3와 v5:
- v3는 초기화되지 않으며, 이후 v5에 대입됩니다. 이는 실행 중 예기치 않은 동작을 일으킬 수 있습니다.
- v4 = v5;:
- v5를 v4에 복사합니다. 하지만 v5도 초기화되지 않았으므로, 결과적으로 v4 또한 예측할 수 없는 값을 가질 가능성이 큽니다.
3. sub_402E10 호출
sub_402E10((unsigned int)sub_401AD5, v4, (unsigned int)&retaddr, 0, 0, a3, (__int64)&v5);
인자 설명:
- (unsigned int)sub_401AD5:
- 함수 포인터를 전달합니다. sub_401AD5는 이 함수 내부에서 호출될 가능성이 있습니다.
- v4:
- 초기화되지 않은 값을 전달합니다.
- (unsigned int)&retaddr:
- retaddr의 주소를 전달합니다. 일반적으로 스택의 반환 주소를 다룰 때 사용됩니다.
- 0, 0:
- 상수 값.
- a3:
- 호출 시 전달받은 세 번째 인자.
- (__int64)&v5:
- v5의 주소를 전달합니다.
sub_402E10 역할 추정:
- 분석 대상:
- 주어진 인자들(sub_401AD5, v4, a3, v5의 주소)을 조합하여 특정 조건을 평가하거나 작업을 수행합니다.
- sub_401AD5:
- 함수 포인터이므로, sub_402E10에서 호출되어 추가적인 작업이 진행될 가능성이 높습니다.
4. __halt()
__halt();
- 프로그램 실행을 멈추는 명령입니다. 이후에는 어떤 작업도 실행되지 않습니다.
- 주로 디버깅 또는 종료 조건에서 사용됩니다.
5. 문제점
- 초기화되지 않은 변수 사용:
- v3와 v5는 초기화되지 않은 값을 가지므로, v4와 v5의 주소를 사용하는 sub_402E10 호출 시 비정상 동작이 발생할 가능성이 큽니다.
- 스택 오프셋 경고:
- // positive sp value has been detected, the output may be wrong! 경고는 스택 포인터의 값이 비정상적으로 설정되어 있다는 것을 의미합니다.
- 스택 프레임 초기화 또는 함수 호출 과정에서 잘못된 메모리 참조가 일어날 가능성을 나타냅니다.
6. 코드 흐름 요약
- start 함수는 호출된 세 인자(a1, a2, a3)를 받고 실행됩니다.
- 초기화되지 않은 변수 v3, v5를 조작하여 v4를 설정합니다.
- sub_402E10 함수를 호출하여 주요 작업을 수행합니다.
- 작업이 끝난 후 __halt()를 호출하여 프로그램을 멈춥니다.
7. 개선 및 확인해야 할 사항
- v3와 v5 초기화:
- 변수에 명시적인 값을 설정해야 실행 중 예측 불가능한 동작을 방지할 수 있습니다.
- sub_402E10와 sub_401AD5 분석:
- 해당 함수들이 어떤 역할을 수행하며, 어떤 조건에서 올바르게 작동하는지 확인해야 합니다.
- 스택 포인터 정렬 확인:
- 스택 오프셋 문제가 발생하지 않도록 스택 프레임의 설정을 명확히 해야 합니다.
위 사항을 바탕으로 디버깅 또는 추가 분석을 진행해야 코드의 정확한 동작을 이해할 수 있습니다.
syb_401ad5값을 클릭해본다
__int64 __fastcall sub_401AD5(__int64 a1, __int64 a2, int a3, int a4, int a5, int a6)
{
__int64 result; // rax
int v7; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v8; // [rsp+8h] [rbp-8h]
v8 = __readfsqword(0x28u);
v7 = 0;
sub_40BB20((unsigned int)&unk_4B6004, (unsigned int)&v7, a3, a4, a5, a6);
if ( v7 == 322376503 )
{
sub_41A400("Correct!");
result = 0LL;
}
else
{
sub_40B990((__int64)"%x is wrong x(\n", v7);
result = 1LL;
}
if ( v8 != __readfsqword(0x28u) )
sub_45A420();
return result;
}
주어진 함수 sub_401AD5의 역할과 로직을 분석한 결과, 이 함수는 특정 조건을 만족했을 때 **"Correct!"**라는 메시지를 출력하며 성공을 나타내고, 그렇지 않을 경우 실패를 나타냅니다. 이를 통해 v7 값을 조작하여 322376503이라는 특정 값을 만들 필요가 있습니다. 주요 부분을 분석해 보겠습니다.
1. 함수의 시그니처
__int64 __fastcall sub_401AD5(__int64 a1, __int64 a2, int a3, int a4, int a5, int a6)
- __fastcall:
- 인자를 레지스터를 통해 전달합니다.
- a1, a2는 64비트 정수형으로, 각각 RCX와 RDX 레지스터를 통해 전달됩니다.
- a3, a4, a5, a6는 정수형으로, 나머지 레지스터를 통해 전달됩니다.
- 반환값은 64비트 정수형(__int64)이며, 함수의 결과로 성공(0) 또는 실패(1)를 나타냅니다.
2. 코드 분석
(1) 로컬 변수 초기화
int v7; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v8; // [rsp+8h] [rbp-8h]
v8 = __readfsqword(0x28u);
v7 = 0;
- v8:
- __readfsqword(0x28u)는 스레드 정보 블록(TIB)의 특정 위치 값을 읽어옵니다. 이는 스택 보호를 위한 stack cookie로, 함수 종료 시 스택 변조 여부를 확인하는 데 사용됩니다.
- v7:
- 초기값은 0입니다. 이후 sub_40BB20 함수 호출에서 수정될 가능성이 있습니다.
(2) sub_40BB20 호출
sub_40BB20((unsigned int)&unk_4B6004, (unsigned int)&v7, a3, a4, a5, a6);
- 목적:
- sub_40BB20 함수는 v7 값을 설정하는 주요 역할을 합니다.
- 입력 인자:
- &unk_4B6004: 외부 데이터 또는 설정 값을 가리키는 포인터.
- &v7: 출력값이 저장될 변수.
- a3, a4, a5, a6: 전달받은 인자.
- 결과:
- v7 값을 수정하여, 이후 조건문에서 평가에 사용됩니다.
(3) 조건 평가
if (v7 == 322376503)
{
sub_41A400("Correct!");
result = 0LL;
}
else
{
sub_40B990((__int64)"%x is wrong x(\n", v7);
result = 1LL;
}
- v7 값이 322376503(0x1337BAB7)과 같으면 "Correct!"를 출력하고 성공(0)을 반환합니다.
- 그렇지 않으면 "%x is wrong x(\n" 포맷 문자열과 함께 v7 값을 출력하며 실패(1)를 반환합니다.
(4) 스택 보호 검증
if (v8 != __readfsqword(0x28u))
sub_45A420();
- 함수 종료 시 v8 값을 재확인합니다.
- 스택 변조가 발생한 경우, 보호 루틴(sub_45A420)이 실행됩니다.
3. sub_40BB20의 역할
sub_40BB20 함수는 v7 값을 수정하는 핵심 함수입니다. 이 함수 내부를 분석하여 v7 값을 322376503으로 설정하기 위한 조건을 확인해야 합니다.
- sub_40BB20는 (unsigned int)&unk_4B6004, (unsigned int)&v7를 포함한 여러 인자를 전달받습니다.
- 목표:
- a3, a4, a5, a6 값 조합을 통해 v7 값을 322376503으로 설정하는 조건을 찾습니다.
4. 결론: "Correct!"를 출력하기 위한 조건
- sub_401AD5 함수가 "Correct!"를 출력하려면 다음이 필요합니다:
- sub_40BB20 호출 이후 v7 값이 정확히 322376503(0x1337BAB7)이어야 합니다.
- 이를 위해:
- a3, a4, a5, a6의 적절한 조합을 찾습니다.
- &unk_4B6004와 관련된 외부 데이터를 확인하여 필요한 값을 설정합니다.
- 디버깅 도구를 사용해 sub_40BB20 내부에서 v7 값을 계산하는 방식을 분석합니다.
- 스택 보호:
- 실행 중 스택 변조가 발생하지 않도록 해야 합니다. 이를 위해 함수의 인자와 로컬 변수 크기를 정확히 맞춰야 합니다.
디버깅 또는 sub_40BB20 분석을 통해 "Correct!" 출력 조건을 정확히 확인할 수 있습니다. 필요하면 이를 도와줄 수 있는 추가 분석을 요청하세요!
correct 출력할려면 322376503이 필요하다.
DH{322376503}
'Dreamhack > Dreamhack Wargame (Challenge)' 카테고리의 다른 글
[80] IT 비전공자 [dreamhack]Type c-j문제 풀기 (0) | 2024.11.28 |
---|---|
[79] IT 비전공자 [dreamhack]out of money문제 풀기 (0) | 2024.11.27 |
[77] IT 비전공자 [dreamhack][wargame.kr] tmitter문제 풀기 (0) | 2024.11.25 |
헤헷헤헷헤헷 드림핵 1000등 (0) | 2024.11.24 |
[76] IT 비전공자 [dreamhack]broken-png문제 풀기 (1) | 2024.11.24 |