Dreamhack/Dreamhack Wargame (Challenge)

[125] IT 비전공자 [dreamhack]set-int문제 풀기

imaginefuture-1 2025. 1. 13. 09:18

 

소스코드다

//Name: chall.c
//Compile: gcc chall.c -o chall -no-pie -fno-stack-protector

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}

int main(int argc, char *argv[]){
    unsigned int a = 0;
    int b = 0;

    initialize();

    printf("Your input : \n");
    scanf("%u", &a);
    if(a > 0){
        b = (int)a + 1;
        if(b == 0){
            printf("Success.\nYour second input : \n");
            scanf("%d", &b);
            if(b < 1){
                b = b-1;
                if(b > 0){
                    system("/bin/sh");
                } else{
                    printf("fail!\n");
                }
            } else{
                printf("Input is too large!\n");
            }            
    
        } else{
            printf("fail!\n");
        }
    } else{
        printf("Input is too small!\n");
    }

    return 0;
}

 

 

이 코드는 특정 조건을 만족시키면 /bin/sh을 실행하는 프로그램입니다. 프로그램의 핵심 동작과 조건을 분석하며, 어떻게 동작하는지 설명하겠습니다.


1. 프로그램 초기화 (initialize 함수)

  • setvbuf:
    • 입력과 출력의 버퍼링을 비활성화합니다. 이는 입력과 출력이 즉각적으로 처리되도록 보장합니다.
  • signal과 alarm:
    • 30초 후에 타이머가 만료되면 TIME OUT 메시지를 출력하고 프로그램을 종료합니다.
    • 이는 프로그램의 실행 시간을 제한하여 의도적인 무한 루프를 방지하기 위한 조치입니다.

2. main 함수 분석

(1) 첫 번째 입력 처리 (scanf("%u", &a);)

  • a는 unsigned int형입니다. 즉, 음수가 아닌 정수만 입력받을 수 있습니다.
  • 조건:
    c
    코드 복사
    if (a > 0) { ... }
    • a가 양수일 경우에만 다음으로 진행합니다.

(2) 두 번째 조건 (b = (int)a + 1;)

  • a를 int로 형변환하고 1을 더해 b에 저장합니다.
  • 조건:
    c
    코드 복사
    if (b == 0) { ... }
    • 여기서 b == 0이 성립하려면 (int)a + 1의 값이 0이어야 합니다.
    • 이는 a가 **0xFFFFFFFF (unsigned 최대값)**일 때 발생합니다.
      • 0xFFFFFFFF + 1은 오버플로우로 인해 0이 됩니다

 

int 타입 오버플로우/언더플로우
int 형의 경우 범위가 –2,147,483,648 ~ 2,147,483,647 이고, 
unsigned int(부호없는 정수)형의 경우 범위가 0 ~ 4,294,967,295 까지입니다.
만약 int 형이 2,147,483,647 + 1 이 되면 최대값을 넘겨져서 –2,147,483,648로 돌아옵니다.
쉽게 이해하자면 값이 고리로 이어져 있다고 생각하면 편합니다!


출처: https://lucykorea414.tistory.com/49 [지은이는 지은이:티스토리]

 

 

 

당신이 올바르게 이해한 것처럼, 2147483648은 signed int의 음수 범위로 인식됩니다. 그 이유를 명확히 설명하겠습니다:


1. 2147483648이 음수값으로 인식되는 이유

2147483648은 32비트 정수에서 signed int의 양수 범위를 초과하는 값입니다.

32비트 signed int 범위

  • 양수 범위: 0 ~ 2147483647 (0x00000000 ~ 0x7FFFFFFF)
  • 음수 범위: -1 ~ -2147483648 (0xFFFFFFFF ~ 0x80000000)

2147483648이 signed int로 처리되는 과정

  1. C 언어에서 unsigned int 값을 signed int로 변환할 때, 비트 패턴은 그대로 유지되지만 부호가 달라집니다.
    • 2147483648은 32비트로 표현하면 0x80000000입니다.
    • 이 값은 signed int에서 최상위 비트(부호 비트)가 1이므로 음수로 해석됩니다.
    • 따라서, 0x80000000은 signed int로는 -2147483648 (INT_MIN)입니다.
  2. b에 2147483648을 넣을 때
    • b는 signed int이므로 2147483648은 -2147483648로 변환됩니다.

2. 왜 2147483648 - 1은 2147483647인가?

다시 계산 과정을 살펴보면:

  • b에 2147483648을 입력하면 b는 -2147483648이 됩니다.
  • b - 1 연산이 수행되면:
    1. -2147483648 - 1은 2의 보수 연산에 따라 오버플로우가 발생합니다.
    2. 오버플로우 결과로 값은 양수의 최대값인 2147483647(INT_MAX)가 됩니다.

3. 핵심 요약

  1. 2147483648이 음수로 인식되는 이유
    • 2147483648 (0x80000000)은 signed int에서 음수의 최소값인 -2147483648로 해석됩니다.
    • 이는 C 언어의 정수 변환 규칙과 2의 보수 표현 방식 때문입니다.
  2. b - 1 연산
    • -2147483648 - 1은 오버플로우를 발생시키며, 결과는 2147483647(양수의 최대값)가 됩니다.
  3. 결론
    • 2147483648은 signed int로 변환될 때 음수로 처리되며, 오버플로우 연산으로 인해 양수 범위로 넘어가는 상황이 발생합니다.