jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다. 3ds Max를 사용해서 게임용 3D 캐릭터를 셋업하는 방법
이를 위해 오랜 실무를 경험해 온 저자의 고급 노하우들이 공개
위 내용은 GameDevForever의 저자분들의 홍보를 위하여 운영진 자체적으로 올린 광고이며 일체의 수익이 없습니다.(밥좀사줘요~)
Posted by 죠쉬
이번에는 클라이언트를 공격하는 공격에 저항하기 위한 프로그래밍 꼼수(?!)들에 대해 다루어 보도록 하겠다. 두 세번에 걸쳐 앞서 이야기 했던 클라이언트를 공격하는 세 가지 방법중 첫번째 방법과 두번째 방법을 막기 위해서 프로그래머가 고려할 수 있는 방법에 대해 제안해 보도록 하겠다.

이전 글에서도 다루었지만, 클라이언트는 기본적으로 해커의 손에 있는 것 이기 때문에 해커는 굉장히 다양한 방법으로 - 조낸 똑똑한 방법으로도, 무식하기 짝이 없는 방식으로도 공격할 수 있다. 그렇기 때문에 그 어떤 방법을 사용해도 끈질긴 해커의 공격에서 클라이언트를 보호할 수 는 없다. 해커의 공격에 저항하는 프로그래밍의 목적은 단 하나, 해커가 지겨워서 혹은 투자한 시간에 비해 얻는게 없다고 느끼게 만들어 목표물을 바꾸게 만드는 것이다.


'내가 이짓을 해서 얻는게 대체 뭐냐...' 라는 표정을 짓고있는 어린 여성 해커 (믿거나 말거나)

해커를 지겹게 만들려면 기존에 잘 알려진 공격 방법을 막는 것 부터 시작해야 한다. 기존에 잘 알려진 공격 방법들은 이미 툴도 많이 나와있기 때문에, 찌질하고 생각없는 것들이 웹 페이지를 띄워 놓거나 책을 펴놓고 한줄한줄 따라하다가 성공하는 불상사가 생기기도 한다. 그런 찌질한 애들이 정말 될거라고 생각 못하고 생각없이 시키는대로 따라하다 실수로 성공해서 뉴스에 나오는 거다. 

그런 가장 간단한 것들 부터 다루고 시작해 보도록 하자. 이번에 다룰 내용은 주로 저장되어있는 파일 - 실행 파일이든 데이터 파일이든 공격자의 하드디스크에 저장되어 있는 파일들에게 공격자들로 부터 비누방울 정도의 얇은 보호막을 치는 방법들이다. 하!지!만! 아무리 얇디 얇은 보호막이지만 띨띨한 공격자들의 눈먼 공격 정도는 충분히 막을 수 있다. 잊지말라, 우리의 노력은 해커의 공격을 100% 완전히 차단할 수 있는 완전무결한 방어책을 만드는 것이 아니다. 해커로 하여금 분노하여 해커 자신의 컴퓨터와 모니터에 도끼질을 하고 후회하게 만드는 것이고, 시도하다 지겨워서 더 재미있어보이는 다른 일을 하게 되기까지 시간을 벌려고 하는 것이다.

0. 들어가기 전에 메모리 구조 이야길 잠시 하겠다.
뭐 모두모두 알고있는 내용일 것 이라 생각 되지만, 그래도 잠시 언급하고 넘어가는게 쬐끔은 도움이 되지 않을까 싶어 부랴부랴 추가 해 보았다. 다음은 일반적인 프로세스의 메모리 구조다.



경우에 따라서는 위 아래가 바뀌어 있을 수 도 있지만, 그림의 표현의 문제일 뿐 둘은 동일한 그림이다. 이 그림에서는 가장 윗쪽이 0번지 가장 아랫쪽이 FFFF....FFFF 번지에 해당된다.

우리가 열심히 프로그램 코드를 작성해서 컴파일을 시도하면, 어셈블리 언어를 거쳐서 기계어로 번역 된 다음에 프로그램 코드 영역에 예쁘게 보존된다. 그리고 프로그램 내에서 사용되는 수 많은 상수들과 스태틱 데이터 - C의 경우 static으로 선언된 변수와 전역변수는 스태틱 데이터 영역에 몰아서 저장된다. 프로그램내에서 선언되고 사용된 위치와 전혀 상관없이 모든 데이터들은 전부 이 영역에 몰아준다. 왜? 편리하니까!

컴파일된 결과물은 프로그램 코드 영역과 스태틱 데이터 영역을 합쳐 놓은 것에 해당되며, 하드디스크에 저장되어 있는 파일의 내용물이 바로 이것이다. 그러므로 프로그램 코드 안에 넣어둔 상수나 스태틱 변수의 값은 모두 해커/크래커의 것 이다.

프로그램이 실행되면, 운영체제는 프로그램 코드영역과 스태틱 데이터 영역의 내용을 하드디스크에서 읽어 들인다음 힙 영역과 스택 영역을 생성하고, 프로그램 코드 영역의 가장 첫 위치로 jump 한다. 보통 프로그램 코드 영역의 가장 첫 위치에 main 함수로 jump하는 기계어 코드가 들어있다. 그리고, main 함수가 실행되는 것이다[각주:1].

힙영역은 *alloc 계열의 메모리 할당 함수가 사용되는 영역이다. 보통 '아래쪽으로 자란다'는 표현이 사용되기는 하지만, 최근의 CPU와 운영체제의 개념에서는 그다지 맞는 표현은 아니다. 스택영역은 함수가 호출될 때 마다 돌아갈 위치가 기록되며, 로컬 변수들이 저장되는 영역이기도 하다. 함수가 호출 될 때 마다 점유 영역이 커지며, 보통 '위쪽으로 자란다'는 표현이 사용된다. 뭐, 아직은 그럭저럭 맞는 표현이기도 하다.

위의 그림에는 각 영역별로 선이 그어져 있지만, 실제로 저렇게 구분되어 있을 리는 없다. 코드가 커진다면 프로그램 A 에서는 스태틱 데이터 영역이지만 프로그램 B 에서는 프로그램 코드 영역일 수 도 있는 것 이다. 힙 영역과 스택 영역도 마찬가지다. 물리적으로 어찌 되었든 간에 논리적으로는 연속된 영역에 존재하는 메모리 이기 때문에 프로그램, 스태틱, 힙, 그리고 스택이 사실은 같은 메모리 이다. 결국, 힙이나 스택에 코드를 저장할 수 있다면, 해당 코드를 실행할 수 도 있다. 바로 여기에서 부터 수많은 해킹 기법이 시작되는 것이다.

그런데... 어쩌라고... 재미 없어 하품하시는 작은 하마 되시겠다. 


1. 파일을 액세스 할 때에는 환경변수를 참조하지 말라
 
경험있는 MMO 클라이언트 프로그래머들이라면 이미 알고 있는 당연한 내용이리라 본다. 환경변수를 참조해서 동적 라이브러리를 찾거나 혹은 파일을 찾는다면, 해커는 가짜 동적 라이브러리 혹은 데이터파일 하나 만들어서 아무데나 던져놓고 환경변수를 바꾸는 것 만으로도 소기의 목적을 달성할 확률이 아주 높아진다.

사실, 환경변수를 참조하지 말라고 하는 것은 '좋은 / 확장성 있는' 프로그램을 만드는 기법에 정면으로 대치되는 어이없는 조언이지만 해커의 공격 이라는 것은 그런 '좋은' 것을 삐딱하게 이용하는 데에서 시작되기 때문에, 어쩔 수 없는 노릇 이기도하다. 몇몇 상용 MMO 게임들은 이런 조건을 충족하기 위해 설치 디렉토리를 변경할 수 없게 고정 하기도 한다. (설마, 그냥 동적 패스 구성할 능력이 안돼서 고정 패스를 쓰는 건 아니겠지? 꿈보다 해몽이 좋은건가?)

2. 외부 프로그램을 실행시키지 말라, 어쩔 수 없다면 절대 패스를 이용하라

외부 프로그램을 실행 시키고 그 실행 결과에 따라 프로그램이 동작하게 만든다면, 그야말로 '나잡아 잡숴 주세요' 라고 해커에게 부탁하는 꼴이 된다. 그러므로 다른 프로그램의 기능을 이용해야 하는 경우 가능하면 그 기능을 내 코드에 어떤 형식으로든 포함 시켜야 한다. 정말 불가능 하다면, 절대패스를 이용하도록 해야 한다.

만약, 액세스 빈도가 잦지 않고 사용자를 기다리게 할 수 있는 상황이라면 보안목적으로 만들어진 해쉬함수들 (SHA, MD5) 등을 이용하여 대상 프로그램/파일이 변조되지 않았다는 것을 먼저 확인하는 것도 해커를 귀찮게 하는 방법이 될 수 있다.

3. 변조 되어서는 안되는 중요한 데이터 파일 이라면 암호화 하라

MMO의 경우 변조함으로서 어떤 이익을 얻을 수 있는 파일은 클라이언트측에 저장하지 않는 것이 당연하다. 그러나 어떤 이유에 의해 도저히 서버로 전달해서 저장할 수 없다면, 혹은 오프라인에서도 혼자 플레이 하다가 그 결과를 서버로 보낼 수 있도록 하는 등의 기능을 구현 하고자 하면 어쩔 수 없이 로컬에 저장해야 하는 경우엔 저장할 때 암호화 하여 저장하고, 로드하기 전에 검증을 해야 한다.

중요한 파일을 암호화 한 경우, 해당 파일을 복호화 하기 위한 키는 서버에서 보내준 것을 사용해야 한다. 키는 반드시 서버에 저장하고, 사용시 서버에서 전달받아 파일을 복호화 한 다음 바로 키를 삭제해야 한다. 암호화 했다고 해도 키와 암호화 된 파일 모두가 로컬에 저장되어 있는 경우에는 - 비록 키가 프로그램 안에 숨겨져 있다고 해도 찾아내어 복호화 하고 수정한 다음에 다시 암호화 할 수 있는 가능성이 있다고 보는게 맞다.

4. 중요한 파일을 로드해서 사용하기 전에는 반드시 검증하라

3에서 언급된 데이터 파일을 포함하여 인증용 라이브러리 같이 프로그램을 수행하는데 있어 중요한 역할을 하는 파일들은 실행 전에 반드시 검증해 주어야 한다. 검증은 SHA나 HAS같은 보안 목적으로 만들어진 해쉬 함수를 활용해야 한다. '파일의 검증'이라는 말을 들으면 바로 떠오르는 것이 아마도 'CRC'일텐데, CRC는 변조를 방지하려는 목적이 아니기 때문에 고의로 변조한 경우에는 찾아내지 못한다는 문제점이 있다. 그러므로 보안 목적으로 만들어진 해쉬 함수를 사용해야 한다.


보이는게 모두 진실은 아니다. 프로포즈 하기 전에도 검증은 해야 한다.
사진속 인물이 궁금하다면 '남태희'라고 구글 형님에게 물어보면 알려준다. 


ㄱ. 검증을 위해서는 보안목적으로 만들어진 해쉬 함수를 사용한다.[각주:2]

보안을 위해 만들어진 해쉬 함수들은 속도 보다는, 공격자가 위조를 막는 것이 첫번째 목표이다. 그렇기 때문에 해쉬 함수를 이용해서 파일을 검증하면, 검증을 회피할 수 있는 공격 프로그램이나 데이터를 만들어 내기가 아주 어렵다[각주:3]. 공격자를 귀찮게 하는, 보안을 위해 만들어진 해쉬 함수들은 다음과 같은 세가지 조건을 가지고 있다.

1. 해쉬 값을 가지고 원래 값을 찾아내기가 아주 어렵다[각주:4].
2. 어떤 데이터의 해쉬값과 동일한 해쉬값을 갖는 다른 데이터를 찾아내기가 아주 어렵다.
3. 같은 해쉬값을 갖는 두 데이터를 찾아내기가 아주 어렵다[각주:5].

추가적으로, 대부분의 블록암호나 보안을 위한 해쉬는 diffusion(확산) 이라는 특성을 가지고 있다. 렌더링에 사용되는 확산하고 별다를바 없는 개념이기야 하겠지만, 암호학에서는 한 비트라도 변경되면 결과물이 완전히 변경되는 효과를 말한다. SHA1을 가지고 예를 들어 보겠다.

SHA1("HELLO2") == 0xf55a1dfb23cb72689274c543ad201c388b52b149
SHA1("HELLO3") == 0x8c0a6d67117649466d1928145bdd4cabeab9ef28

2의 아스키 코드 값은 32 - 0010 0000b 이고 3의 아스키 코드 값은 33 - 0010 0001b 이므로, 그야말로 여섯바이트 중 한 비트가 변경 되었음에도 불구하고 결과값의 40바이트 전체가 완전히 변경 된 것을 볼 수 있다.

이렇듯 조금만 바꿔도 검증용 데이터는 완전히 바뀌는 데다가, 같은 해쉬값을 갖는 다른 - 변조된 파일을 만드는 것은 아주 어렵기 때문에, 해커는 파일 자체를 수정하는 것 외의 다른 방법을 찾으려고 시도하게 될 확률이 높아진다.

ㄴ. 검증에 사용되는 데이터는 항상 상수로 사용하라

한마디로 표현하자면, 그리고 가장 무식한 방법을 들자면, 다음과 같이 쓰라는 말이다.

if(data[0] != 0xf55a) return 0;
if(data[1] != 0x1dfb) return 0;
if(data[2] != 0x23cb) return 0;
...
if(data[18] != 0x8b52) return 0;
if(data[19] != 0xb149) return 0;
return 1; 


이때 data 배열은 파일을 보안을 위해 만들어진 해쉬함수를 이용해 얻어진 해쉬값이다.

매크로 함수를 만든다면 아래와 같은 방법도 나쁘지 않을 수 있다.

(data[0] != 0xf55a)? 0: (data[1] != 0x1dfb)? 0: ...

        (data[18] != 0x8b52)? 0: (data[19] != 0xb149)? 0: 1; 


무식하다는 점에 있어서는 위쪽의 소스와 별다를 바 없지만, 매크로 함수에는 조금 더 나을 수도 있지 않을 까 싶기도 하다라는 생각을 해볼 수 있지 않을까라는 입장이 될 수도 있을 법한 소스 이다(응?).

물론 위의 방법은 아주 무식하고, 아주 귀찮은 방법이다. 검증 데이터를 배열에 때려박아 넣고 for 루프 한번 휙 돌려주면 해결 될텐데, 그야말로 프로그램 완전 초짜나 쓸만한 닥질로 보일 것 이다. 더 나아가 편하게 검증 데이터를 변경하기 위해 - 검증되는 라이브러리를 재 컴파일 할 때 마다 검증데이터를 변경해야 하니, 전역으로 잡아주거나, 스태틱 멤버 상수로 잡아주면 편리하게 작업을 할 수 있을 것이다. 심지어는 빌드 스크립트에 검증 데이터를 자동으로 생성해서 헤더에 박아넣는 일을 할 수 도 있을 것이다.

그러나, 그렇게 하면 프로그래머가 편리한 만큼 해커도 편리하게 검증 키를 찾아낼 수 있다. 왜? 컴파일러가 식별자를 갖는 상수 값들은 전부 스태틱 영역에 예쁘게 모아주기 때문에, 해커는 문자열을 찾아낼 때와 동일한 방법으로 실행파일의 스태틱 영역만 뒤져보면 손쉽게 키를 찾아낼 수 있다. 게다가 검증에 사용되는 데이터의 길이는 고정되어 있으니 찾기도, 바꿔 넣기도 쉽다.

ㄷ. 검증용 함수는 가능하면 인라인 함수로 만들어라

인라인 함수의 장점중 하나는, '나는 하나만 만들지만 컴파일 된 결과물에는 같은 코드가 여러번 반복된다'이다. 이렇게 해주면 공격자는 리버스를 시도할 때 불필요하게 긴 코드가 여기저기 반복되어 존재하는 것으로 보게 된다. 그리고 정말 자기가 필요로하는 코드 영역이 어디인지 찾기 힘들어진다.

이중에 네가 수정해야 하는 코드가 어느거냥?


5. 중요한 파일이라 암호화 해야 한다면. 압축한 후 암호화 하라

아무리 강력한 블록암호 기법이고, 키를 아주 잘 숨겨서 공격자가 찾을 수 없다고 해도 블록암호 자체를 공격해서 키를 알아내는 공격법은 있다. 가장 잘 알려진 공격 방법은 '선형 공격; Linear Cryptanalysis'과 '차분 공격; Differential Cryptanalysis' 이다. 이 방법을 이용하면 충분한 양의 암호문과 시간만 있으면 암호문에서 키를 알아낼 수 도 있다.

그러나, 파일을 먼저 압축한 후에 암호화 하면 1) 암호화 해야 하는 데이터의 양이 줄어들고 (물론 데이터의 특성에 따라 커질 수 도 있다) 2) 설령 블록암호 공격기법을 통해 키를 알아냈다고 해도 암호가 풀린 데이터가 압축되어 있으면 정말 공격에 성공 했는지 여부도 확신하기 쉽지 않게 된다.

암호를 풀었는데 이상한 데이터가 나온다면


당연히 해커는 암호를 풀어내는데 어려움을 느끼게 될 것 이고, 띨띨한 초보자 라면 프로그램이 공격에 성공했다고 메시지를 출력했는데도 불구하고 만들어진 파일이 여전히 의미를 알 수 없는 바이너리 파일이기에 그냥 프로그램이 오동작 했다고 판단할 확률이 높아진다.

주의할 점 중 하나는, 파일의 첫 세바이트를 해당 파일이 어떤 형태의 파일인지 기록하는 표준이 있다는 사실이다. 그렇기 때문에 자신이 사용하는 압축 함수가 완성된 압축 데이터의 첫 세바이트에 그런 정보를 기록해서 주는지 아닌지를 확인해 보고, 만일 기록해 준다면 제거해 주어야 한다. 힘들게 압축해서 암호화 했는데 공격자가 그 세바이트를 보고 공격에 성공했고, 압축을 풀면 된다는 사실을 알게 된다면, OTL 좌절 인거다. 게다가 압축 방법 까지 알려주는 친절까지 베푼 셈이 되는 거다.

할거면 좀 제대로 하지그랬어
 
6. 암호화 할 때에는 암호화할 데이터의 처음에 랜덤 값을 추가 하라

블록암호는 확산 - diffusion 이라는 특성을 갖고 있다[각주:6]. 암호화 되는 데이터중 한 비트가 바뀌면 결과 전체에 그 영향이 확산되어 완전히 다른 결과를 얻게 된다. 그러므로 파일의 제일 앞에 랜덤 값이 들어간다면 같은 데이터를 암호화 해도 매번 다른 암호문을 얻게 되므로 공격자를 혼란에 빠뜨릴 수 있다.

단, 블록암호의 확산은 한 단위 - 블록암호의 종류에 따라 다르겠지만 가장 많이 쓰이는 AES의 경우 최대 256비트 까지, 보통 128비트에만 영향을 주게 된다. 이 크기를 넘는 경우에는 운용모드(Operation Mode)라는 개념이 사용되어 여러 블록을 암호화 하게 된다. 일반적으로 블록암호에 익숙하지 않은 사람이 암호화 하는데 쉽게 사용하는 운용모드는 ECB라는 방식인데 가장 쉽게 깨지는 방식이다. ECB를 사용하면, 처음에 랜덤 값을 넣어도 가장 첫 블록만 확산의 영향을 받게 되므로 암호화 하는 효과가 가장 약하다. 그러니 chaining이 되는 다른 방식을 사용해야만 한다. 다시 말하지만, 블록암호를 이용하여 암호화 할때엔 절대 ECB 모드를 사용해서는 안된다.

가장 단순하고 쓰기 쉽지만 그다지 쓸모 없는 ECB 방식의 암호화,
ECB가 나쁘지 않은 경우는 한 블록 이하를 암호화 할 때 뿐이다.

7. 운용모드를 사용하여 데이터를 암호화 한다면, 초기화 벡터(Initialization Vector)는 저장된 값을 쓰지 말라

프로그램이 실행된 후에 생성해낸 값을 초기화 벡터로 사용하는 편이 해커를 귀찮게 만들 수 있다. 초기화 벡터란 운용모드에서 같은 암호화 키를 사용해도 다른 암호문을 만드는 효과를 갖도록 하는 추가 정보인데, 경험이 없는 프로그래머들중 많은 수가 0을 쓰거나 암호 키를 그대로 사용한다. 아무래도 정확한 의미를 모르는 상황에서 주어진 샘플 코드를 그대로 사용하다보니 생기는 문제이고, 샘플 코드를 만드는 사람 입장에서도 이 값을 선택할 때 적당한 것이 없기 때문에 보통 상수를 넣어 샘플 코드를 작성하기 때문이다. 그러나 초기화 벡터를 잘 이용하면 공격자를 골치아프게 만들 수 있다.

초기화 벡터를 얻어내는 것에 대한 예를 들자면, 아주 중요한 파일의 파일 크기를 해쉬 함수에 넣어서 만들어진 값을 암호화 할 때 쓰는 초기화 벡터로 사용하면 된다. 물론, 그 중요한 파일은 파일의 크기가 변경되거나 하면 안된다. 항상 일정한 크기여야 한다. 이렇게 해주면 해커는 코드를 분석하기 전에는 암호화 할 때 사용된 초기화 벡터가 뭔지 알 방법이 없게된다. 좋은 초기화 벡터를 선택하는 방법은 프로그래머 자신의 창의력을 발휘해 보는 것도 재미 있을 것이다.

주의할 점이 하나 있다. 실행시에 만들어 내는 초기화 벡터는 사용하기 직전에 계산해 내고, 사용한 직후에 0 값을 채워 넣어서 완전히 지워줘야 한다. 초기화 벡터는 첫번째 블럭을 암호화 할 때 단 한번 사용되므로, 첫번째 블럭을 암호화 한 다음에 반드시 각 바이트마다 0을 채워넣어서 지워야 한다. (물론 다음번 벡터 값을 덮어 씌워도 무방하다. 일단 최초의 벡터값을 알 수 없게 하는게 가장 중요하다.) 아니면 힘들여 창의력을 발휘한 보람 없이 해커는 초기화 벡터를 계산해내는 방법을 알아낼 필요 없이 단순히 메모리를 스캔 하는 것 만으로 초기화 벡터 얻어낼 수 있게 될 것이다.

*     *     *

조낸 재미있는 글을 만들어야 하는데... 정말 쉽지 않네요. 역시 원자재 값이 많이 들지 않은 의상을 입고 있는 젊은 처자들의 사진을 끌어들이는 수 밖에 없는 저질 글인 건가... 어흑!

  1. 바이러스류는 바로 이런점을 이용해서 동작합니다. 스태틱 데이터 영역 끝쪽에 바이러스 코드를 심고, 가장 첫 위치의 점프 주소를 바이러스 코드의 시작 주소로 변경한 후, 바이러스의 리턴 주소를 main 함수의 시작주로로 바꾸어 놓습니다(바이러스 코드 부분이 호출된 후 스택을 조작합니다). 그러면 운영체제가 프로그램을 로드하고 실행할 때, main() 함수가 아니라 바이러스 코드를 불러주게 됩니다. 바이러스는 할일 다 하고 리턴만 하면 되는 겁니다. 쉽지요? [본문으로]
  2. 검증을 위해 만들어진 해쉬함수의 대표적인 예는 MD5, SHA-1, SHA-256, HAS-160 등이 있습니다. 이중에 MD5와 SHA1은 안전하지 않은 해쉬 함수들로 알려져 있으며, 충돌쌍 - 해쉬함수의 세 조건을 깨는 두 값을 발견하였습니다. 그러나 아직도 많이 사용되고 있기도 하지요. HAS-160은 SHA-1 계열의 해쉬로 한국정보진흥원이 개발해서 발표한 국산 해쉬함수 입니다. [본문으로]
  3. 여기에서 말하는 '아주 어렵다'는 말의 의미는, '그 결과를 가지고 의미 있는 작업을 할 수 있을만한 시간내에는 풀수 없는'이라는 뜻이다. 조금 비약해서 예를 들자면 '10년동안 비밀로 해야하는 문서가 있는데, 이 문서를 암호화 하면, 암호화된 문서를 가지고 키를 알아내기 어렵다.'는 말의 의미는 '10년 내에는 키를 알아낼 수 없다'는 의미로 이해하면 된다. [본문으로]
  4. '해쉬함수가 깨기 어렵다'는 말의 의미는 '위의 세가지 특성중 최소한 하나의 답을 알아내려면 천문학적인 시간이 필요하다'는 의미로 이해해도 무방하다. [본문으로]
  5. 언뜻 보기엔 2번하고 3번이 비슷해 보이겠지만, 그 의미는 다르다. 그리고, 게임에서 데이터나 프로그램 코드를 위조하는 것을 막는 목적으로는 3번의 특성은 필요 없다. 3번의 특성은 이중장부를 만들고 싶어하는 사람들을 엿먹이기 위해 필요한 특성이다. [본문으로]
  6. 이 diffusion 효과에 대해서는 4-ㄱ 에서 이미 설명을 했으니 모두모두 잘 아시리라 믿씹니다. [본문으로]

댓글을 달아 주세요

  1. Favicon of http://gamedevforever.com ozlael 2012.02.09 10:27 신고  댓글주소  수정/삭제  댓글쓰기

    우와 짤이 흥해요~~ 나도 저런 딸 ㅠㅠ (똑똑한 해커딸 케케케)

  2. Favicon of http://gamedevforever.com 김포프 2012.02.14 04:41 신고  댓글주소  수정/삭제  댓글쓰기

    근데 왜.. quick time plugin이 필요한거죠... 이미지중 하나보려면?

  3. Favicon of http://gamedevforever.com cagetu 2012.02.16 11:04 신고  댓글주소  수정/삭제  댓글쓰기

    우와... 잘 봤습니다. ㅎㅎ

  4. Favicon of http://병맛블로그 책읽는잉여 2012.02.22 17:05 신고  댓글주소  수정/삭제  댓글쓰기

    좋은 내용 감사합니다.

  5. Favicon of http://gamedevforever.com 김포프 2012.02.25 06:22 신고  댓글주소  수정/삭제  댓글쓰기

    한번 더 정독했는데 정말 좋은 글~

  6. Favicon of http://Junios.net Junios 2012.03.07 18:22 신고  댓글주소  수정/삭제  댓글쓰기

    중요한 내용 잘 보고 갑니다.



티스토리 툴바