버퍼는 임시기억공간 이라는포괄적인개념이기때문에여러곳에존재할수있습니다. 즉, CPU 에도버퍼가존재할수있으며, 하드디스크에도존재할수있고, CD- ROM 이나프린터에도존재할수있습니다. 그리고앞의예제에서보신바와같이일반프로그램에도존재할수있습니다. 이번시간엔프로그램에서버퍼를사용하는법, 그중에서도 C 언어에서버퍼를사용하는방법에대해배워보겠습니다. C 언어에서버퍼를사용하는가장쉬운방법은바로변수를선언하는것인데, C 언어에아직익숙하지않은분들을위해먼저변수를선언하여버퍼를할당받는방법에대해배워보겠습니다. 우선프로그래머는얼마나큰크기의변수를할당받을지결정을내려야합니다. 이크기의기본단위는바이트 (Byte) 입니다. C 언어는다양한크기에대한변수형 (Type) 을기본으로제공하고있는데, 그중자주사용되는것들만요약하면다음과같습니다. 26
변수형 char short int int long int 크기 1바이트 2바이트 4바이트 4바이트 단, int 형변수의크기는컴파일러의종류및 CPU 레지스터의크기에따라달라질수있기때문에, 본서적에선 32bit 컴파일러 &CPU 를기준으로설명하겠습니다. 이제각변수형이얼마나큰수를기억할수있는지계산해보겠습니다. char 형변수는 1 바이트이고, 이는 8 비트와같습니다. 그럼계산기프로그램을실행시킨후 Bin 버튼을눌러 2 진수모드로바꾼후에 8 비트, 즉 8 개의 0 과 1 로표현할수있는최대값인 11111111 을입력해봅시다. (Windows 7 용계산기를기준의예제입니다. XP 에선계산기의설정을공학용으로바꾸어사용하시면됩니다.) 그리고 Dec 버튼을눌러이값을 10 진수로변환하면, 27
버퍼 오버플로우-왕기초편 3.c언어에서 버퍼 사용하기 이처럼 255가 됩니다. 하지만 실제 char형 변수가 사용할 수 있는 최대 값은 11111111(8비트)이 아니라 1111111(7비트)입니다. 왜냐 하면 맨 앞의 첫 비트는 현재 값이 양수인지 음수인지 를 나타내는 부호 비트로 쓰이기 때문입니다. 이에 맞게 다시 계산을 해보겠습니다. 28
이처럼실제로는 127 이 char 형변수로표현할수있는최대값입니다. 그럼이번엔반대로 char 형변수로표현할수있는최소값은몇일까요? 앞서얘기한첫번째비트인부호비트는 0 일때 양수 1 일때 음수 임을의미합니다. 따라서최소값을구하기위해선음수가양수보다작은수이기때문에부호비트가무조건 1 이어야합니다. 그리고나머지 7 비트로표현할수있는최소수는 0000000 입니다. 이에맞게계산을해보겠습니다. (char 형에적합하게부호비트를적용시키기위해 Byte 에체크를해줍니다.) 29
이처럼 char 형으로표현할수있는가장작은수는 -128 임을알았습니다. 이런식으로각변수형별로표현할수있는최소 / 최대값을정리하면다음과같습니다. 변수형 크기 최소 ~ 최대값 char 1바이트 -128부터 127 short int 2바이트 -32768부터 32767 int 4바이트 -2147483648부터 2147483647 long int 4바이트 -2147483648부터 2147483647 그런데경우에따라선 음수 가아예필요없을때도있습니다. 예를들어서울에서부산, 혹은지구에서화성까지의거리를출력하는프로그램이라면음수값은필요없습니다. 음수의거리란있을수없기때문입니다. 그래서 C 언어는무조건양수만사용할수있는변수형역시제공합니다. 그럼첫번째 1 비트를다시사용할수있게되어 char 형의최대크기는 11111111(8 자리 ) 가됩니다. 이처럼부호없는변수는변수형앞에 unsigned( 부호없는 ) 를붙여주면됩니다. unsigned char, unsigned int 와같은식입니다. 그럼변수의크기는그대로이지만, 표현할수있는값의범위가달라지게됩니다. 변수형 크기 최소 ~ 최대값 unsigned char 1바이트 0부터 255 unsigned short int 2바이트 0부터 65535 unsigned int 4바이트 0부터 4294967295 unsigned long int 4바이트 0부터 4294967295 이렇게해서변수의크기및표현범위에대해알아보았습니다. 30
이제 C 언어를이용하여변수를할당받고사용하는연습을해봅시다. 우선가장기본적인 1 바이트를할당받아보겠습니다. char c; 이 char c 라는구문은 1바이트크기의변수를메모리 (RAM) 에할당받아라 는명령을의미합니다. 이제여러분은 1바이트크기내의값들을이변수에저장해서사용할수있습니다. 다음과같이말입니다../03/ex1.c char c; c = 20; printf( 버퍼에뭐가들었을까 ~? : %d\n, c); 소스를컴파일하여실행해보겠습니다. $ cd 03 $ gcc -o ex1 ex1.c $./ex1 버퍼에뭐가들었을까 ~? : 20 $ 이처럼간단하게변수를할당받고사용하는연습을해보았습니다. 그런데앞서배웠던변수형들중에가장용량이큰건 4 바이트였습니다. 그럼만약그이상크기의데이터를변수에저장하려면어떻게해야할까요? 31
예를들어 Hackerschool 이라는문자열을변수에저장하기위해선문자열끝의 NULL 문자까지합하여총 13 바이트가필요합니다. 4 바이트짜리변수를사용한다고해도 9 바이트가부족합니다. 이를해결하기위한쉬운방법중하나는 1바이트크기의 char 형변수를 13개선언하고각각에한문자씩을저장하는것입니다../03/ex2.c char c1 = H ; char c2 = a ; char c3 = c ; char c4 = k ; char c5 = e ; char c6 = r ; char c7 = s ; char c8 = c ; char c9 = h ; char c10 = o ; char c11 = o ; char c12 = l ; char c13 = \0 ; 하지만누가봐도이방법은번거롭고어설퍼보입니다. 그래서 C 언어는 배열변수 라는것을제공합니다. 이는여러개의변수를쉽게선언하고사용할수있게도와줍니다../03/ex3.c char c[13] = H, a, c, k, e, r, s, c, h, o, o, l, \0 ; 32
이렇게하면 c[0] 에서부터 c[12] 까지총 13 개의 char 형변수가선언되고, 이변수각각에지정된문자가저장됩니다. 여기서문자열을더쉽게사용하려면다음과같이해도됩니다../03/ex4.c char c[13] = Hackerschool ; 그리고조금더쉽게사용하는방법도있습니다. 만약 13이라는배열크기를지정해주지않으면, C언어는필요한배열크기를자동으로계산해줍니다../03/ex5.c char c[] = Hackerschool ; // char c[13] 과동일 33
이제이변수를버퍼로사용하려면어떻게하면될까요? 방법은간단합니다. 어디선가로부터 ( 예를들면키보드 ) 입력받은데이터를이변수에저장하고, 출력하거나다른곳으로보내는용도로사용하면이변수는곧버퍼가되는것입니다. 이처럼버퍼는개념적인용어이기때문에 데이터를한곳에서다른곳으로이동시키기위한임시공간 이라는의미에부합된다면그무엇이든지버퍼가될수있습니다. 지난강좌에사용되었던예제를다시보겠습니다../01/test.c main() char name[20]; printf( 당신의이름을입력하세요. : ); gets(name); printf( 아, 당신의이름은 %s이군요.\n, name); 여기서 char name[20] 부분이바로버퍼로사용될변수를선언하는부분입니다. 그리고변수형이 char 이기때문에기본크기는 1 바이트이고, 이것이총 20 개의배열변수로선언되었기때문에총크기는 1 x 20 = 20 바이트입니다. 즉, 버퍼의크기는 20 바이트가됩니다. 그렇기때문에 20 바이트이상의값이이버퍼로전달되면문제가생기는것입니다. 34