2011년6월13일_이상한 나라의 이상한 CM샘의 이상한 소스(HexaViewer)를 이상하게 분석하는 이상한 보고서를 이상한 나
이상한 CM샘의 이상한 소스(Hexa Viewer) 전체 |
소스코드…수업 마치고 갑자기 들어 오셔서 던져 주신 이상한 소스코드...
1: #include <stdio.h>
2:
3: #define ROW_LINE 16 // 메모리 출력 행 수
4:
5:
6: void MSDFunction(void *, unsigned int);
7:
8: int main()
9: {
10: int iNum = 0x12345678;
11: MSDFunction(&iNum, 10);
12:
13: return 0;
14: }
15:
16: void MSDFunction(void *vAddr, unsigned int print_line)
17: // Memory Status Display Function
18: /*******************************************************************************
19: 기능 : 인수로 넘겨받은 주소로부터 ROW_LINE개 단위를 1줄로 print_line의 숫자 만큼
20: 화면에 출력
21: 인수 : 출력할 대상이 있는 곳의 주소값, 메모리 출력시 출력 라인 수
22: 반환값 : void
23: *******************************************************************************/
24: {
25: unsigned char *addr = (unsigned char *)vAddr;
26: unsigned int loop_temp = 0; // 반복문을 위한 임시 변수 선언
27: unsigned char memory_dump[ROW_LINE]; // 반환된 메모리값을 임시로 저장
28:
29: if (0 == *addr)
30: {
31: return;
32: }
33: else
34: {
35: printf(" Address "); // 화면 상단 자리 표시를 위한 출력
36: }
37:
38: while (loop_temp < ROW_LINE) // Hex 부분 출력
39: {
40: printf("%02X ", loop_temp++);
41: }
42:
43: putchar(' ');
44: loop_temp = 0;
45:
46: while (loop_temp < ROW_LINE) // ASCII 부분 출력
47: {
48: printf("%X", loop_temp++);
49: }
50:
51: putchar('\n');
52:
53: while (0 < print_line) // Data 부분 출력 루프 시작
54: {
55: loop_temp = 0;
56: printf("0x%08X ", addr); // 메모리 주소 출력
57:
58: while (1) // 메모리 읽어 오기 및 hex 출력 시작
59: {
60: // 메모리 주소에 위치한 값을 배열에 저장
61: *(memory_dump + loop_temp) = *addr;
62:
63: // 배열에 저장된 값 출력
64: printf("%02X ", *(memory_dump + loop_temp));
65:
66: ++loop_temp;
67: ++addr;
68:
69: if (0 == (loop_temp % ROW_LINE)) // ROW_LINE개를 출력하였으면 loop 종료
70: {
71: break;
72: }
73: else
74: {
75: }
76: } // 메모리 읽어 오기 및 hex 출력 끝
77:
78: putchar(' ');
79: loop_temp = 0;
80:
81: while (1) // ASCII 부분 출력 루프 시작
82: {
83: if (0 == *(memory_dump + loop_temp))
84: {
85: putchar('.'); // 널 문자 대치
86: }
87: else if (32 > *(memory_dump + loop_temp))
88: {
89: putchar('*'); // 제어 문자 대치
90: }
91: else if (127 <= *(memory_dump + loop_temp))
92: {
93: putchar('*'); // 그래픽 문자 대치
94: }
95: else
96: {
97: putchar(*(memory_dump + loop_temp));
98: }
99:
100: ++loop_temp;
101:
102: if (0 == (loop_temp % ROW_LINE)) // ROW_LINE개를 출력하였으면 loop 종료
103: {
104: break;
105: }
106: else
107: {
108: }
109: } // ASCII 부분 출력 루프 끝
110:
111: putchar('\n');
112: --print_line;
113: } // Data 출력 루프 끝
114:
115: putchar('\n');
116: }
117:
분석 |
전처리부 |
1: #include <stdio.h>
2:
3: #define ROW_LINE 16 // 메모리 출력 행 수
4:
5: void MSDFunction(void *, unsigned int);
표준 입출력 라이브러리는 다들 아실거고…
ROW_LINE은 화면에 출력되는 메모리값의 행의 수라고 주석에 명시되어 있으나…
실제 아래의 소스를 들을 보면 행의 수가 아닌 열의 수이다.
그러니 COL_LINE으로 명칭변경을 하여야 할 것이다.
처음부터 이상한 나라의 이상한 CM샘의 이상한 소스 코드가 시작되었다.
MSDFunction( ) 함수의 원형이 선언이 되었다. 함수의 원형에 있는 인수리스트에는 자료형만 적어도 된다.
MSD이름만 봐선 무슨일을 하는 함수인지 전혀 모르겠다.
이상해! 이상해!
main( ) 프로그램의 시작 |
1: int main()
2: {
3: int iNum = 0x12345678;
4: MSDFunction(&iNum, 10);
5:
6: return 0;
7: }
iNum에 HEXA값을 확인하기 쉽도록 16진수 12345678을 넣고 그 주소와 화면에 출력할 행의 수 10을 인자로 넣는다.
여기서 첫 번째 인자자리가 함수의 원형을 보면 void*로 특정한 형태가 없는 포인터형이다.
void* (void 포인터)란?
가리키는 곳의 크기를 모른다. void와는 완전 다른 개념으로 char인지 short인지 int인지 알 수 없다는 뜻이다.
즉, 가리키는 곳이 1Byte가 될 수도 2Bytes가 될 수도 있다. 마치 포커에서 조커와 비슷하다고 볼 수 있다.
예를 들어 아래와 같이,
1: int A = 100;
2: int *ip;
3: char *cp;
4: float *fp;
5: void *vp;
6:
7: ip = &A;
8: cp = ip; //경고메세지를 출력하나 포인터라 크기는 같아 대입은 된다.
9: vp = ip; //경고메세지가 출력되지 않고 잘 된다.
10: vp = cp; //경고메세지가 출력되지 않고 잘 된다. (vp는 아무 타입이나 다 받아 들임,)
11: //혈액형 AB형과 비슷하군...A, B ,O형 어느 혈액형이나 수혈가능함.
12: *ip = 3; //A의 값을 3으로 바꿈.
13: *vp = 9; //에러! 쓸 곳의 크기를 몰라.
14: *vp = (int *)9; //int형 포인터로 캐스팅하면 됨.
15:
16: ip = vp; //역은 안 됨. ip는 크기가 정해져 있으나 vp는 크기를 몰라
17: int B = *vp; /* *를 붙여 값을 읽어와 대입하려 해도 안 됨. */
void *vp는 AB형 혈액형과 같아 여러 혈액형의 혈액을 받을 수 있으나 다른 혈액형을 가진 사람에게 줄 수 없다.
(상기의 코드는 테스트를 해보지 못 하였으니 100%신뢰하지 말 것)
1: int iNum = 0x12345678;
2: char cNum = 100;
3: short sNum = 65000;
4:
5: MSDFuntion(&iNum, 10); //int형을 받아 들였고,
6: MSDFuntion(&cNum, 10); //char형을 받아 들였고,
7: MSDFuntion(&sNum, 10); /*short형을 받아 들여 어떤 자료형이든 다 받아 들인다.*/
하나의 함수로 여러 자료형의 변수를 받아 들일 수 있어 매우 편리해 보인다.
Memory Status Display Function |
1: void MSDFunction(void *vAddr, unsigned int print_line)
2: // Memory Status Display Function
3: /*******************************************************************************
4: 기능 : 인수로 넘겨받은 주소로부터 ROW_LINE개 단위를 1줄로 print_line의 숫자 만큼
5: 화면에 출력
6: 인수 : 출력할 대상이 있는 곳의 주소값, 메모리 출력시 출력 라인 수
7: 반환값 : void
8: *******************************************************************************/
MSD가 옛날 라면에 첨가된 화학조미료 이름인줄 알았는데,
그게 아니라 메모리 상태를 화면에 출력하는 함수다. HexaView( )과 같다고 할 수 있다.
이렇게 함수에 박스주석을 달아 주면 오랜 시간이 흘러도 자신이 만든 소스를 쉽게 파악할 수 있다.
즉, 외계인코드를 방지할 수 있다.
1: unsigned char *addr = (unsigned char *)vAddr;
2: unsigned int loop_temp = 0; // 반복문을 위한 임시 변수 선언
3: unsigned char memory_dump[ROW_LINE]; /* 반환된 메모리값을 임시로 저장 */
unsigned char형 포인터 변수 addr을 선언하고 인수받은 void포인터변수 vAddr의
//여기서 부터 편집하면 됨.