1. 정의
 typedef 기존데이터형 새이름;
 
 ex) typedef int NUM;
       typedef char STR;
       typedef struct STUDENT;

typedef는 매번 앞에 struct나 union, enum 키워드를 써야하는 구조체나 공용체, 열거체를 정의할 때 유용하다. 'struct 태그명'을 typedef로 이름을 지정하면 사용하기가 편리하다.

  typedef struct point{
   int x;
   int y;
 }POINT; // struct point를 POINT라는 이름으로 정의

위와 같이 struct point를 POINT라고 정의하면 POINT를 새로운 데이터형으로 사용할 수 있다.

 POINT p1, p2; // 이것은 struct point p1, p2;와 같은 의미이다.

수학에서 치환과 비슷한 개념이라고 생각하면 된다.
위와 같이 구조체를 정의하면서 typedef를 정의할 수도 있고, 구조체를 정의한 후에 할 수도 있다.

  struct point{
   int x;
   int y;
 };
 typedef struct point POINT;

typedef로 정의된 데이터형도 원형 그대로 사용이 가능하다.

 struct point p1;
 POINT p2;

<예제>
 #include <stdio.h>
 struct point{
  int x;
  int y;
 };
 typedef struct point POINT;

 int main(void){
   struct point p1 = {10, 20};
   POINT p2;
   p2 = p1;
   printf("p2의 좌표 : %d, %d\n', p2.x, p2.y);
   return 0;
}

2. typedef 사용 목적
 typedef를 사용하면 이식성(portability)과 가독성(readability)에 큰 도움이 된다.
  struct point{
   int x;
   int y;
 }; // 1번

  struct point{
   double x;
   double y;
 }; // 2번

 만약 point 구조체가 1번과 같을 때 변수는 int형이다. 그런데 만약 실수를 사용하는 경우가 생긴다면 2번과 같이 구조체를 새로 정의해야 한다. point 구조체를 사용하는 함수가 존재하거나 다른 곳에서 자주 사용되고 있다면 일일이 모두 수정해야만 한다. 하지만 typedef를 사용하면 간단하다.

 typedef int nType;
 struct point{
   nType x;
   nType y;
 }; // 1번

 typedef double nType;
 struct point{
   nType x;
   nType y;
 }; // 2번
 typedef 정의 부분에서 데이터형만 변경함으로써 간단하게 수정이 가능하다.

 가독성 면에선 다음과 같은 경우를 가정해보자. unsigned char는 문자를 저장할 수도 있고 1바이트 정수형을 저장할 수도 있다. 이 경우 어떤 용도인지 명확히 구분할 때 typedef를 사용할 수 있다.
 typedef unsigned char oneByte;
 oneByte data;

'프로그래밍 > C' 카테고리의 다른 글

assert 매크로 사용법  (0) 2014.01.27
이중배열과 포인터 문제 하나  (0) 2013.12.01
malloc & free 기본 사용법  (0) 2013.07.23
공용체와 열거체  (0) 2011.01.19
구조체  (0) 2010.10.23
배열과 포인터의 관계  (0) 2010.10.09
포인터 (Pointer)  (0) 2010.10.09
1. 공용체
 공용체는 여러 멤버들이 메모리를 공유하게 하는 것이다. 즉, 모든 멤버들의 주소가 같다. 구조체는 메모리에
순차적으로 멤버를 할당하지만 공용체는 같은 메모리를 함께 사용하는 이다.

union 태그명{
 데이터형 멤버형;
 데이터형 멤버형;
 ...
};

ex)
union data{
 unsigned int num;
 unsigned char arr[4];
}; 

 union data d1; //공용체 변수의 선언

 공용체 변수는 메모리에 할당될 때 같은 주소에 할당되는데 공용체 크기는 가장 큰 멤버의 크기와 같다.
위의 예에서는 멤버 모두 4바이트이므로 전체 크기도 4바이트가 된다.
<--------------------------------------------------- num --------------------------------------------------->
 arr[0] arr[1]  arr[2]  arr[3] 
<-------------------------------------------------- 4바이트-------------------------------------------------->

 공용체의 초기화나 접근 방법은 구조체와 동일하게 {}와 .을 사용한다. 다만 초기화할 때 여러 멤버 중 한 번에
하나만 사용할 수 있으므로 첫 번째 멤버의 초기값만 지정한다.

<예제> 공용체의 사용 예
 #include <stdio.h>
union data{
 unsigned int num;
 unsigned char arr[4];
};
int main(void){
union data d1;
int i;
printf("data 공용체의 크기 : %d\n", sizeof(union data));
d1.num = 0x12345678;
printf("d1.num = %08x\n", d1.num);
for(i=0;i<4;i++)
 printf("d1.arr[%d] = %02x\n", i, d1.arr[i]);
return 0;
}

d1.num을 0x12345678로 초기화했기 때문에 같은 메모미를 사용하는 d1.arr 역시 같은 값을 가진다. d1.arr는 배열이므로
4바이트인 num의 값을 바이트 단위로 접근이 가능하다. 따라서 실행결과는 다음과 같다.

 data 공용체의 크기 : 4
d1.num = 12345678
d1.arr[0] = 78
d1.arr[1] = 56
d1.arr[2] = 34
d1.arr[3] = 12

※ 리틀 엔디안과 빅 엔디안
리틀 엔디안(little endian) : 최하위 바이트부터 메모리에 저장하는 방식 (인텔 계열 CPU)
빅 엔디안(big endian) : 최상위 바이트부터 메모리에 저장하는 방식 (모토로라 계열 CPU)

                                                                     unsugned int num = 0x12345678;

 12  34 56  78    78  56  34  12 
0x1000          0x1001           0x1002          0x1003                                0x1000          0x1001           0x1002          0x1003
                             빅 엔디안 방식                                                                            리틀 엔디안 방식

PC는 주로 인텔 계열의 CPU를 사용하므로 예제의 결과도 리틀 엔디안 방식으로 메모리에 값이 저장된 것을 확인할 수 있다.

공용체가 유용하게 사용되는 경우를 살펴보자.

 struct info{
 char name[10];
 int job_code;
 char company_name[20];
 char school_name [20];
};
job_code가 0이면 학생, 1이면 회사원이라고 가정하자. 이때 위와 같이 구조체로 정의하면 job_code가 어떤 것이라도
일단 메모리에 company_name 변수와 school_name 변수가 할당된다. 따라서 학생일 경우 company_name 변수를
사용하지 않고 회사원일 경우 school_name 변수를 사용하지 않으므로 메모리가 낭비된다.
이런 경우 공용체를 이용해서 구조체를 정의하면 메모리 낭비를 막을 수 있다.

 struct info{
 char name[10];
 int job_code;
union{
 char company_name[20];
 char school_name [20];
}job_info;
};

2. 열거체
열거체(enumerated type)는 열거형이라고도 하며, 정수형의 일종이다.

 enum 태그명 {열거상수1, 열거상수2, ...};

ex) enum week {sun, mon, tue, wed, thu, fri, sat};
 위와 같이 열거체 변수에는 열거체 정의에 나열된 열거상수 값 중 하나를 저장해야 한다.
 열거체와 열거상수는 프로그램의 가독성(readability)을 향상시키는 기능을 한다.


'프로그래밍 > C' 카테고리의 다른 글

이중배열과 포인터 문제 하나  (0) 2013.12.01
malloc & free 기본 사용법  (0) 2013.07.23
typedef  (0) 2011.01.22
구조체  (0) 2010.10.23
배열과 포인터의 관계  (0) 2010.10.09
포인터 (Pointer)  (0) 2010.10.09
선택정렬 (Selection Sort)  (0) 2010.10.09
SQL Injection은 웹 사이트의 취약점을 이용하여 권한 없는 사용자가 정보를 취할 수 있는 공격기법이다.
아주 기초적인 면을 설명할텐데 그 전에 Database와 Query문에 대해서 조금 알 필요가 있다.
Database와 Query문에 대해 간단하게 설명하겠지만 관련 자료를 찾아서 한 번 읽어본다면 훨씬 이해하기
쉬울 것이다. 여기서 쓰이는 Database와 Query문의 수준도 크게 어려운 것이 아니기 때문이다.

Database에는 테이블이란 것이 있고 그것에 각각 필드가 존재한다.
test란 테이블 내에 userid와 userpw란 필드가 있다고 가정하자.
그리고 userid에는 softs, userpw에는 1234란 값이 저장되어 있다고 가정하고 다음의 Query문을 보자.
(※ 좀 더 쉽게 설명하자면 회원가입을 할 때 아이디와 비밀번호를 입력하고 회원가입을 누르면 그 아이디와 비밀번호가
해당 서비스 제공자의 DB(Datebase)에 저장되는데 그때 userid와 userpw라는 필드에 각각 그 값이 저장되어 보관되는
것이다.)

일단 여기서 사용할 Query문의 기본 형식은 아래와 같다.

 select 필드명1,필드명2 from 테이블명;

이제 다음과 같은 Query문을 보내보자.

 select uesrid,userpw from test where userid='softs' and userpw='1234'

이것은 Database의 test 테이블에서 userid의 값이 softs이고 userpw의 값이 1234과 일치한 것을 찾는 것인데
Database에 그 값이 정상적으로 등록되어 있을 때의 결과는 다음과 같다.

 userid='softs'(true) and userpw='1234' (true)

true and true는 true가 되어서 정상적으로 작동이 된다.
(※ 아이디와 비밀번호가 일치하면 로그인이 되는 상황을 생각하면 된다.)

하지만 아래와 같은 Query문을 보내면 어떻게 될까?

 select uesrid,userpw from test where userid='softs' and userpw='4321'

위와 같은 경우에 결과는 다음과 같다.

 userid='softs'(true) and userpw='4321' (false)

true and false는 false가 되므로 작동하지 않는다.
(※ 아이디와 비밀번호가 일치하지 않으면 로그인이 되지 않는 상황을 생각하면 된다.)

그러면 이 정도의 지식을 가지고 다음 데모 사이트에서 SQL Injection을 실습하면서 익혀보자.
http://demo.testfire.net/bank/login.aspx 
(위 사이트의 실습 방법은 웹서핑 중 어떤 블로그에서 배웠고 이 포스팅은 그것을 복습한 내용이다.)


먼저 아무 값이나 입력해보자.
이때 입력한 값을 가지고 Query문을 추측해보면 아래와 같다.

 select uesrid,userpw from login where uesrid='guest' and userpw='1234'
(※ 테이블 이름을 login, Username과 Password 필드의 이름을 uesrid, userpw로 가정했을 때의 Query문이다.)

당연히 등록되지 않은 값이므로 결과는 아래와 같다.

 userid='guest'(false) and userpw='1234'(false)

따라서 로그인이 되지 않는다.

이번엔 Username과 Password에 각각 'a 라고 입력하고 로그인을 해보자.


이때에 Query는 아래와 같이 보내졌을 것이다.

 userid=''a' and userpw=''a'

Query문은 userid='' and userpw='' 처럼 '로 시작하고 '로 끝이 나야하는데 위와 같은 경우에는
''로 끝나고 a'가 선언 되어 오류가 발생하는 것이다.

이 오류를 이용하여 Query문을 수정하여 Injection을 시도해보자.

Username에 admin을 Password에 'or'1'='1을 입력하고 로그인을 해보자.



로그인에 성공하였다.
이유가 뭘까?
일단 Username에 admin을 Password에 'or'1'='1을 입력했을 때의 Query문을 추측해보자.

 select uesrid,userpw from account where username='admin' and password=''or'1'='1'

위와 같이 보내졌을텐데 위의 결과는 아래와 같다. 


 userid='admin'(true) and userpw=''(false)or'1'='1'(true

true and (false or true)인데 (false or true)는 true이므로 결국true and true가 되어서 최종적으로 true가 된다.
다른 방법으로는 주석문을 이용하는 것이다. SQL의 주석은 --를 사용하는데 --뒤에 입력된 부분은 모두 삭제되어
전송된다.
따라서 Username에 admin'--을 Password에 아무 값이나 입력하고 로그인하면 로그인에 성공하게 된다.
이때의 Query문과 처리 결과를 살펴보면 아래와 같다. 


 select uesrid,userpw from login where userid='admin'--' and userpw='aaaa' 

 select uesrid,userpw from login where userid='admin'(true)

이렇게 Username이 true가 되어서 로그인이 된다.
이런 취약점에 대한 간단한 대응으로는 아이디와 비밀번호를 입력할 때 특수문자의 제한을 두는 방법이 있다.
실제로 대형 포털사이트에서 '을 입력하려고 시도해도 입력되지 않는다. 

'네트워크 > 해킹' 카테고리의 다른 글

ARP Spoofing  (0) 2011.01.02

+ Recent posts