본문 바로가기

My Study/Programming&Theory

간단한 C코드에서 나는 오류


(위 코드를 실행하면 런타임 에러가 뜨는데 왜 뜨는지 몰라서 분석을 해보았습니다.)
위와 같이 하나의 숫자를 받은 다음 그 숫자를 문자 하나로 출력해주는 프로그램 입니다.
65를 입력하게 되면 아스키코드 65는 'A' 이므로 'A'가 출력이 될것입니다.

컴파일을 해보면 당연히 컴파일 상에서는 오류가 없습니다.
제가 실험한 컴파일 옵션은 Debug모드로 하고 실험을 했습니다.
하지만 실행을 시켜보겠습니다.

실행결과는 정상적으로 나오는데 런타임에러가 뜨고 있었습니다. 결과를 보니 스택에 문제가 있는거 같습니다.
그냥 소스코드만 봐서는 답이 안나와서 디버거로 직접 봐보았습니다.


이 부분이 scanf로 수를 입력 받는 부분입니다. EAX로 전달하는 값이 [EBP-5]의 주소를 전달하고 있습니다.
(입력받은 수를 저장할 주소)
처음에 값을 전달 받을 때 EBP에서 시작해서 처음 4Byte는 오버플로우가 일어났나 안 일어났나를 검사하기 위해 비워둡니다. 
그렇기 때문에 [EBP-1]이 아닌 처음 4Byte를 비워둔 [EBP-5]의 주소를 전달하는 것입니다. 당연히 입력받을 변수의 자료형을 char라고 정의했기 때문에 1Byte만 할당한 것입니다. 이때 입력을 받기 전 스택을 봐보겠습니다.


노란색으로 된 부분이 EBP부분입니다. 그 전 함수 스택의 EBP가 들어있고 위로는 비워져있습니다.
이제 우리의 예상으로는 수를 입력 받으면 EBP-5자리인 빨간색 네모친 부분에 0x41이라는 값이 들어올 것입니다.
수를 입력해보고 다시 스택을 봐보겠습니다.

우리가 예상한 자리에는 41이라는 값이 정상적으로 들어왔습니다. 하지만 빨간색 네모친 부분에 0이라는 값이 들어와있습니다.
분명히 저 부분은 오버플로우 났는지 안났는지 검사하기 위한 부분이므로 저 4Byte중 1Byte라도 수정을 가하게 되면 아까 같은 런타임 에러가 뜰것입니다. ( 무시하면 정상 진행됨.. 그 전 함수의 EBP와 리턴주소를 건들진 안았으므로.. )

왜 그러면 저 자리에 0 이들어오는 것일까요??

위에서 scanf로 입력받을 때 서식문자를 '%d'로 쓴 걸 알 수 있습니다. %d는 십진 정수를 받는 서식문자 이므로 4Byte를 받는 줄 알고 메모리에 4Byte만큼의 공간을 잡는 것입니다. 그렇기 때문에 결론적으로 [EBP-5]에서부터 4Byte를 쓰게됩니다. 이러면 당연히 건들면 안될 부분을 건들게 되는 것입니다. 즉, 스택에 값이 잘못 씌워져서 런타임 에러가 발생하게 되는 것입니다.

위 부분이 검사를 하는 부분입니다. 위에서 [EDX+EBX]에는 CC000000이라는 값이 들어있습니다. CCCCCCCC과 비교해서 다르므로 점프를 하지 않게 되고 CALL에서 걸리게 되는 것입니다.
아마 저 점프문을 수정시켜 무조건 점프를 하게 되면 런타임 에러는 발생하지 않을 것입니다.

저 간단한 C소스를 몰라 이렇게 까지 분석을 해보았습니다 ;;

그리고 위에서 처음 4Byte가 버퍼 오버플로우,언더플로우 체크 때문에 비워진다고 했는데 Visual Stuido에서 아래와 같은 기능 때문에 들어가게됩니다.

빨간색 네모 친 부분입니다.