2014.04.27 14:13

[ windbg command 모음집 ] 암기해야 할 명령어들 정리 

‘srv*C: \WebSymbols*http://msdl.microsoft.com/download/symbols’

----------------- 일반적인 명령어들 ----------------------

uf      ==    (gdb) disass 


bl     ==    breakpoint list

bp    ==    set BreakPoint

bu    ==    set Unresolved Breakpoint (defers the actual setting of the breakpoint until the moudule is loaded)

ba    ==    break on address

bc     ==    breakpoin clear 

be, bd    ==    breakpoint enable, disable


k      ==     callstack 을 보여준다 .

lm     ==     load 된 파일과 unload 된 모듈들을 보여준다. 

ex) lm vm msvcrt

lmD   ==     -||- ( output in Debugger Markup Language )

  

dt nt!_TEB  //Thread enviroment block 설정들을 보여줌 == !teb

dt nt!_PEB  //Process Enviroment Block 설정들을 보여줌 ==  !peb

ex )dt nt!_PEB -r @$peb // @$peb = address of our process’s PEB (see pseudo-register syntax)

ex2)dt nt!_TEB Addr   // full TEB dump


!dlls  == dll 정보들을 보여준다. 

!dlls -c kernel32       ==        same as before for kernel32 only  ( kernel32 대신 다른것을 써도된다)

ex) !dlls -c msvcrt 


!tls   ==  tls 정보들을 보여준다


!mgreloc     ==     relocation 정보를 보여준다.

!dh kernel32     ==      kernel32 의 헤더정보를 보여준다.

 

~         ==        thread statues for all thread

~0        ==         thread status for thread 0 

~.           ==       thread statues for currently active thread

~*        ==       thread status for all threads with some extra info (priority, startAdress)

~*k      ==       call stacks for all thread ~ !uniqstack

~<trehad>s     ==    set current thread

!gle     ==     get last error


?       ==    ' = ' 의미와 비슷하다 결과를 알려줌

ex) ? 00130000 - 0012c0000

result ) evalute expression : 16384 = 00100000


!uniqstack  == 모든 thread들에 대한 현재 프로세스의 콜스택을 보여준다.


k == 콜스택을 보여준다

kP == P의 의미는 각 호출되는 함수들의 full 파라미터를 의미함.

kf  == f == distance between adjacent frames to be displayed (useful to check stack consumption of each frame

kv == v == display FPO information + calling convention 

kb == 각각의 함수들의 처음 3파라미터를 보여준다. 

dds == stack trace 


------------------------------Memory handling ------------------------------------------------

dd     ==    double word 형태로 보여줌

da     ==    문자열 형태로 보여줌 

du     ==    유니코드 형태로 보여줌 

f        ==    fill memory

dds     ==    words 와 심볼들을 보여준다.

ddp     ==     참조되는 메모리들을 보여준다.

!address -RegionUsageStack    ==    Dispaly stack regions for all threads in the process

----------------------------- Heap Information    ------------------------------------------------

!heap ?     ==    간단 요약

!heap -h        ==    범위내의 힙 리스트 나열 

!heap -s 0     ==    summary for all heaps

!heap -p     ==    Gflags settings HeapHandle list

!heap -p -all ==    Details of all allocations in all heaps in the process 

dds == stack trace 


-------------------------------------------------------------------------------------------------

!locks       ==    프로세스 크리티컬 섹션같은 락킹된 리스트를 보여줌 -v 옵션을 주면 모두 출력 

!cs [ Opt ] [CsAddr ] == 크리티컬 섹션트리를 보여줌

!avrf -cs  == Display a list of deleted critical section



[ Automatic Pseudo -Registers ]

$ra         ==    스택의 현재 주소를 반환   ex ) g $ra

$ip         ==     Instruction Pointer   ( x86 = EIP , itanium=IIP , x64 = RIP )  

$exentry  ==    현재 프로세스의 첫 EP 값

$retreg     ==    리턴되는 주소를 갖는 값 (EAX, RAX ) 

$peb        ==    process environment block 

$peb        ==   Address of the thread environment block of current Thread

$tpid        ==    Process ID (PID)

$tid        ==    Thread ID(TID)



------------------ Meta or Dot-command 들 ----------------------

.sympath  == 심볼 경로들을 보여줌 ( 설정도 가능 )  

.cls   == 화면 초기화

.lastevent == 방금전 했던 명령어 

.detach == process  deteach

.if == ?? 

.reload /f ntdll.dll   // ntdll 이 없다고 뜰때 해결

 




-------------------- 확장 명령어 ------------------------------

!analyze == 심볼정보등 프로세스의 자체 분석내용을 나열해준다.

!address == section 헤더들의 주소들도 알려주고.. 뭔가 더하는것같은데.. 잘모르겠다

!handle  == 사용되는 핸들러들을 보여준다.

!peb == PEB 파일을 보여줌. 


!ext.help ==  일반적인 확장 도움말

!Uext.help  == 사용자모드의 확장 ( OS에 특화되지 않은 것 )

!Ntsdexts.help == 사용자모드의 확장( OS에 특화됨 )

!Kdexts.help == kernel-Mode Extensions 

!logexts.help == Logger Extensions 

!clr10/sos.help == debugging ManagedCode


 

------------------------------- Symbol 관련  -------------------------------

_NT_SYMBOL_PATH=srv*C:\Symbols\MsSymbols*http://msdl.microsoft.com/download/symbols; //명령어아님


.sympath          ==     심볼을 보여주거나 셋팅이 가능하게 해줌

.sympath + XY  ==     XY 디렉토리를 심볼 경로에 추가함

!sym noisy       ==     심볼 검색에 대한 정보를 표시 

ld kernel32       ==     kernel32 dll 을 불러온다.

ld *                 ==     모든 모듈을 위해 심볼을 불러온다.

.reload            ==     심볼 정보를 모두 재로드한다.

. kernel32!*      ==     kernel32에 대한 자료를 검토한다.

dt ntdll!*          ==     모든 종류의 ntdll 을 보여준다.


 --------------------------------  소스 관련 -------------------------------

.srcpath          == 소스파일을 불러오거나 셋팅할 수 있다.

.srcpath + XY   == XY폴더를 소스파일 검색 폴더에 추가한다.






[ heap 메모리 릭 찾기 ]

0:001> !heap -stat -h 0

Allocations statistics for

heap @ 00150000

group-by: TOTSIZE max-display: 20

size #blocks total ( %) (percent of total busy bytes)

100000 101 - 10100000 (99.99) 0x101 * 1MB allocated. Looks like a good candidate for a memory leak.

928 2 - 1250 (0.00)

64 24 - e10 (0.00)

0:001> !heap -flt s 100000 get all allocations with size: 100000

_DPH_HEAP_ROOT @ 151000

Freed and decommitted blocks

DPH_HEAP_BLOCK : VirtAddr VirtSize

Busy allocations

DPH_HEAP_BLOCK : UserAddr UserSize - VirtAddr VirtSize

024f0698 : 13831000 00100000 - 13830000 00102000

024f0620 : 13721000 00100000 - 13720000 00102000

… There should be 0x101 entries with size 100000 output here.

Let’s take the first one with UserAddr=0x13831000

0:001> !heap -p -a 13831000

address 13831000 found in

_DPH_HEAP_ROOT @ 151000

in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)

24f0698: 13831000 100000 - 13830000 102000

7c91b298 ntdll!RtlAllocateHeap+0x00000e64

0045b74e TestApp!CMyDlg ::OnBnClicked_DoMemoryLeak+0x0000003e

0040b122 TestApp!_AfxDispatchCmdMsg+0x00000043

0040b32f TestApp!CCmdTarget ::OnCmdMsg+0x00000118

00408838 TestApp!CDialog ::OnCmdMsg+0x0000001b




Posted by k1rha
2014.04.27 11:46

[ windbg explotiable 를 예측해주는 플러그인 이다 ] 

 dll 파일을 windbg 의 wintext 폴더에 넣어주고 ( window 비트수에 맞춰서.,.)


크래시가 터졌을때 아래 명령어로 검사를 해 줄 수 있다.



MSECExtensions.zip


You may need to explicitly load the MSEC DLL. If you installed it to the winext sub-directory, you can load

it with 


  !load winext\msec.dll

!exploitable

Gives an analysis, including a proposed bug title


!exploitable -v

Gives a verbose analysis


!exploitable -m

Gives the same output as -v, but formatted for easy machine 



[ 출처 : http://pgnsc.tistory.com/311 ] 



Posted by k1rha
2013.09.28 11:54

[ 파이썬 해킹 프로그래밍] 퍼저 환경 구축하기 pydbg 설치하기 fuzzer enviroment install


파이썬 해킹프로그래밍에 있는 fuzzer 환경을 구축하기 위한 방법이다.

1. python 설치  [ http://python.org ]


2. python 환경변수 등록 

[ 시스템 환경 변수 $PATH 에 C:\python\을 등록  하여 어디에서든 사용 할 수 있도록 한다]


3. paimei 설치 [ python 디버거를 설치]

  

OpenRCE-paimei-d78f574.rar


위파일을 다운로드 받고 dist 폴더로 들어가면 설치 파일이 이 있다. 더블클릭하여 설치한다.

설치하고나면  "C:\Python27\Lib\site-packages\pydbg\" 가 생긴다.


4. pydbg 덮어 씌우기


pydasm.pyd


"C:\Python27\Lib\site-packages\pydbg\"  에 위파일을 덮어 씌운다.

 


5. __init__ 에서 ctype 구조체 임폴트 시키기 

C:\Python27\Lib\ctypes\__init__.py 파일을 열어서 아래 부분을 추가해준다.


 

from _ctypes import RTLD_LOCAL, RTLD_GLOBAL

from _ctypes import ArgumentError


from struct import calcsize as _calcsize

from _ctypes import Structure as _ctypesStructure      #추가부분

class Strucure(_ctypesStructure): pass                   #추가부분



6. 이후 fuzz_hash.py 를 실행시킨다.

  

fuzz_hash.py


위 파일이 들어간 폴더에 퍼징할 샘플 파일들과 hash_DB.txt(emptytext) 를 생성해서 넣어준다. hash_DB.txt 는 크래시난 정보들이 저장되며, 크래시가 터질경우 crash 폴더를 자동으로 생성하여 샘플 파일을 넣는다. 


[ 실행법 ]

python 파일명 -t "타겟 프로그램" -s "샘플 위치"


$python fuzz_hash.py -t "C:\Program Files (x86)\GRETECH\GomPlayer\GOM.exe" -s "C:\k1rha\sample\"






Posted by k1rha
2013.01.29 21:26

[출처 : 파이썬 해킹프로그래밍 ] 



간단한 디버거을 만드는 큰 흐름은 아래 와 같다.




위 내용을 우선 winapi를 사용하는 방법으로 파이썬에서 실행시키는 것부터 시작 하였다.

아래는 기본적인 createProcessA() 함수를 받을수 있도록 선언된 상태에서 calc 를 실행시키는 부분까지 이다. 

즉 위 표에서 파란색 부분만이다.






test.py



import my_debugger


debugger = my_debugger.debugger()

debugger.load("C:\\WINDOWS\\system32\\calc.exe")








my_debugger_defines.py



from ctypes import *


#Ctypes 형태의 타입을 마이크로 소포트의 타입으로 매핑시켜서 사용하기 위한 정의이다.

# 이 이후부터는 아래의 마이크로 소포트타입형은 우측의 ctype으로 재정의 된다.


WORD    =   c_ushort

DWORD   =   c_ulong

LPBYTE  =   POINTER(c_ubyte)

LPTSTR  =   POINTER(c_char)

HANDLE  =   c_void_p


DEBUG_PROCESS = 0x00000001

CREATE_NEW_CONSOLE  =   0x00000010


#윈도우에서 프로세스를 직접 실행시키는 방법은 CreateProcessA() 함수를 호출해야 한다.

#아래 구조체는  CreateProccessA() 를위한 구조체이다. 

class STARTUPINFO(Structure):

    

    _fields_ = [

                    ("cb",      DWORD),

                    ("lpReserved",  LPTSTR),

                    ("lpDesktop",   LPTSTR),

                    ("lpTitle", LPTSTR),

                    ("dwX", DWORD),

                    ("dwY",DWORD),

                    ("dwXSize",DWORD),

                    ("dwYSize",DWORD),

                    ("dwXCountChars",DWORD),

                    ("dwYCountChars",DWORD),

                    ("dwFillAttribute",DWORD),

                    ("dwFlags",DWORD),

                    ("wShowWindow",WORD),

                    ("cbReserved2",WORD),

                    ("lpReserved2",LPBYTE),

                    ("hStdInput",HANDLE),

                    ("hStdOutput",HANDLE),

                    ("hStdError",HANDLE),

                ]

    

#실행한 프로세스의 정보를 닮도록 구성된 구조체 이다. 

#어떠한 프로세스를 실행하면 프로세스 아이디와 쓰레드아이디 정보가 여기에 담긴다

class PROCESS_INFORMATION(Structure):

    _fields_=[

                  ("hProcess", HANDLE),

                  ("hThread",HANDLE),

                  ("dwProcessId",DWORD),

                  ("dwThreadId",DWORD),          

              ]

        

        




my_debugger.py



from ctypes import *

from my_debugger_defines import *


kernel32 = windll.kernel32


class debugger():

    

    #생성자와 같은 연락을 하고 초기화를 담당한다.

    def __init__(self):

        pass

    

    #클래스 debgger가 로드될시 자기 자신과 실행할주소가 들어가게된다. 첫번째 인자는 반드시 self 여야 한다.

    

    def load(self,path_to_exe):

        

        #계산기의 GUI를 보고자 한다면 creation_flags를 

        #CREATE_NEW_CONSOLE로 설정하면된다.

        creation_flags = DEBUG_PROCESS

        

        #구조체를 인스턴스화시킨다.

        startupinfo = STARTUPINFO()

        process_information = PROCESS_INFORMATION()

        

        #다음의 두 옵션은 프로세스가 도립적인 창으로 실행되게 만들어준다

        #이는 STARTUPINFO struct 구조체의 설정 내용에 따라 디버깅 프로세스에 어떤 영향을 미치는지 보여준다.

        startupinfo.dwFlags = 0x1

        startupinfo_wShowWindow = 0x0

        

        #다음에는 STARTUPINFO struct 구조체 자신의 크기를 나타내는 cb변수 값을 초기화 한다.

        

        

        startupinfo.cb = sizeof(startupinfo)

        

        if kernel32.CreateProcessA(path_to_exe,

                                   None,

                                   None,

                                   None,

                                   None,

                                   creation_flags,

                                   None,

                                   None,

                                   byref(startupinfo),

                                   byref(process_information)):

            

                                                print "[*]We have successfully lanunched the process!"

                                                print "[*]Pid : %d" %process_information.dwProcessId

        

        else:

            print "[*]Error :0x%08x." %kernel32.GetLastError()

            





Posted by k1rha
2013.01.29 11:15

 [ 출처 : http://mystic24.egloos.com/901967 ]

 

 

Fuzz란 소프트웨어에 랜덤 데이터를 입력함으로써 소프트웨어의 조직적인 실패를 유발함으로써 소프트웨어의 보안적 취약점을 찾아내는 것을 의미하며 Fuzzing은 오늘날 가장 효과적인 소프트웨어의 보안 테스트로 접근되고 있다.

최근 관련 서적을 읽으면서 아직 초반 부분정도로 밖에 읽지는 않았지만 지금까지 읽는 내용을 정리해보려고 한다.


취약점을 발견하는 방법
* White Box Testing
  - 소스코드 리뷰를 통해 프로그램의 취약점을 발견하는 방법
  - 관련 코드 감시 툴
   - RATS, ITS4, SPlint, FlawFinder, jLint, CodeSpy

* Black Box Testing
  - 단계적인 테스팅을 통한 프로그램의 관찰
  - 자동화된 테스팅, Fuzzing

* Gray Box Testing
 - White Box Test 와 Black Box Test 의 중간 단계
 - 이진 데이터의 감시
  - LogiScan, BugScam, Inspector, SecurityReview, BinAudit

Fuzzer에 의해 전형적으로 들어나 있는 취약점
 * Access Control 의 결점
 * 잘못된 로직 디자인
 * 백도어
 * 메모리의 부패 (엉뚱한 메모리 값)

Fuzzing의 방법
 * 테스트 케이스의 선행
 * 랜덤 데이터의 주입
 * 프로토콜의 변형 테스트
 * 변형 또는 거칠게 주입시키는 테스트
 * 자동화된 프로토콜을 생성

Fuzzer의 종류
 * 로컬 Fuzzer
  - 프로그램 실행 변수(Command-Line) 및 환경 변수, 파일포멧을 통한 Fuzzer
 * 원격 조작
 * 네트워크 프로토콜
 * 웹 어플리케이션
 * 웹 브라우져
 * In-Memory
 * 프레임워크

효과적인 Fuzzing을 위한 필요조건
 * 문서화
 * 재사용성
 * 프로세스의 상태와 깊이
 * 트래킹, 코드보호
 * 에러 검출
  - 에러를 모니터링 하여 전달
 * 리소스 제한


자동화와 데이터의 생산
 * 관련 툴 및 라이브러리
  - Ethereal. Wireshark
  - LIBDASM, LIBDISASM
  - Libnet, LibnetNT
  - LinPCSP
  - Metro Packet Library
  - PTrace
  - Python Extensions
 
 * 데이터의 생성과 Fuzz 발견법
  - 정수값
   - 예를 들어, 다음과 같은 코드가 있다고 하자

int size = red_ccr_size(packet);
buffer = (char*) malloc(size + 1);


    이러한 코드의 접근은 메모리 오버플로우가 발생 할 수 있다. (즉 size 값이 0xFFFFFFFF 의 극한의 데이터라면 size + 1 = 0, 메모리 오버플로우가 발생하게 된다. 반대의 경우도 언더플로우가 발생할 수 있다).
   만약 데이터를 할당시에 size에 곱하기가 이루어 질 경우 이 좀더 낮은 숫자값으로도 발생

buffer = (char*) malloc((size * 2) + 1);

  - 스트링의 반복
  - 필드의 경계부호
   - ex) !@#$%^&*()-_=+{}|\;:'",<.>/?~`
  - 포멧화된 문자열
  - 문자 전환
  - Directory 검색
  - 명령어 주입

환경 변수와 인수 Fuzzing (Local Fuzzing)
 * Command-Line 인수
 * 환경변수

 명령어의 인수나 환경변수를 통해 옵션을 포함시켜 해당 값에 대한 어플리케이션의 반응을 살펴본다.
 
웹 어플리이션 및 서버 Fuzzing
 네트워크 프로토콜을 통하여 패킷을 전송하여 웹메일, 게시판, 위키, 웹블로그 등등을 Fuzzing한다. 주로 HTTP 통신을 하며, 디렉토리 탐색, 패킷 데이터의 오버플로우, SQL의 주입(로그인 데이터), XSS 스크립팅을 통해 HTTP 상태코드 및 웹서버의 에러 메시지, 통신 연결 을 검출하여 취약점을 발견한다.

 * 관련 웹 어플리케이션
  - SPIKE Proxy, WebScarab, SPI Fuzzer, Codenomicon, beSTROM


현재까지 읽은 부분은 10단원 까지로, 갑자기 읽어야 하는 책이 생긴 이유로 이후는 나중에 시간이 될때 계속 읽어 볼 예정이다.

 

Posted by k1rha
2013.01.29 09:53

출처 : http://kamakaru.tistory.com/225

 

fopen()으로 헥사 값을 고치기 위한 방법(The method of modify hex code via fopen)

 

 

C standard library에는 여러 함수가 존재한다.
게중에는 fopen, fwrite 와 같이 파일을 제어 할 수 있는 함수들 역시 존재한다.
여기서 알아 볼 것은 fopen이다.

fopen은 파일을 여는데 사용하는 함수이다.
fopen의 함수 원형은

FILE * fopen( const char * filename, const char * mode )

인데, 파일의 이름과 mode를 인자로 받는다. mode는 문자열로 되어 있으며 해당 함수에서 해당 문자를 parsing해서 원하는 mode로 설정하는 형태를 취하고 있다.
fopen은 실제 여러 옵션자가 존재하는데,
r, w, a 로 존재한다. ( 모드 설명은 아래 그림 참고 - 출처 : http://www.winapi.co.kr )

모드

설명

r

읽기 전용으로 파일을 연다.  모드로  파일은 읽을 수만 있으며 데이터를 기록하지는 못한다. 만약 파일이 없을 경우 에러가 리턴된다.

w

쓰기 위해 파일을 연다.  모드로  파일은 쓰기만 가능하며 읽지는 못한다. 도스나윈도우즈의 파일은 쓰기 전용 속성이 없지만 스트림은 쓰기 전용 상태로   있다.파일이 없으면 새로 만들고 이미 존재한다면 기존의 파일은 지워진다.

a

추가를 위해 파일을 연다. 추가란 파일의 끝에 다른 정보를   넣는다는 뜻이다. 모드로  파일은 오픈 직후에 FP 파일의 끝으로 이동한다. 파일이 없으면 새로 만든다.

r+

읽고 쓰기가 가능하도록 파일을 연다. 파일이 없을 경우 에러가 리턴된다.

w+

읽고 쓰기가 가능하도록 파일을 연다. 파일이 없을 경우 새로 만든다.

a+

읽기와 추가가 가능하도록 파일을 연다. 파일이 없으면 새로 만든다.



이런 옵션을 사용해서 우리가 원하는 파일의 입출력을 수정할 수 있다.


그렇다면 데이터 파일의 중간의 값을 변경하기 위해서는 어떤 옵션자를 주면 되는 것일까?


임시로 만든 파일에는 위와 같은 데이터가 있다. 여기서 0x02 번지의 값인 0x32 라는 데이터 값을 0x20 으로 변경하고 싶다. 이럴땐 어떤 파일 모드로 열어야 될까?
흔히하는 방법으로 write를 수행하기 위하여 w를 하거나 혹은 a 라는 모드를 사용한다. ( windows, linux에서 모두 binary로 처리한다는 가정하에)
만약 위와 같은 방법으로 데이터를 수정하려고 한다면 심각한 고민거리에 빠져들게 된다.

즉, w의 옵션자를 사용해서 해당 위치를 fseek 함수를 통해 파일 포인터를 이동시키게 된다면, 파일이 작성되는 순간부터 해당 데이터의 뒤에 저장된 데이터에 대한 안정성은 보장해 주지 못하게 된다.

직접 실험해 보면 알겠지만, 00 , 31, 32, 33, 34 라는 데이터 나열에서 32 라는 값을 변경하기 원하여 32에 64라는 데이터를 집어 넣는다고 가정할 때, 32의 지점으로 fseek으로 파일 포인터를 이동시켜 64라는 데이터를 집어 넣는다. 그렇게 된다면 파일내의 데이터는 00, 00, 64 로 뒤에 33, 34에 대한 데이터가 삭제됨은 물론 앞의 데이터 까지 버려지게 된다.

a라는 옵션을 줘서 모드를 바꾸게 된다면 어떻게 될까? 다시 위의 가정 대로, 00, 31, 32, 33, 34 라는 데이터가 존재한다. 마찬가지로 32 라는 데이터 값을 64로 바꾸고 싶다. fseek을 통해서 파일 포인터를 이동시킨후 64라는 값을 삽입한다. 이와 같은 경우는 00, 31, 32, 33, 34, 64 라는 값이 나온다. 즉 값이 파일에 추가되어 기록이 되는 것이다.

그렇다면 '+' 연산자를 사용하여 넣으면 어떻게 될까? 안타깝게도 w+ 는 기본 모태가 'w' 이므로 데이터 기록시 w와 별반 다를게 없이 된다.( 즉 앞의 데이터는 삭제되고, 뒤의 데이터 역시 날라간다. )
a+ 역시 마찬가지의 반응을 보였다.
rw 라는 옵션을 통해 read + write 가 되게 하면 않겠는가? 라고 물으시는 분들이 있을 것이다. 궁금하신 분들은 직접 실험을 해보면 될 것이다. 잘못된 접근으로 오류가 발생함을 알 수 있을 것이다.

그렇다면 마지막 남은 'r+'에 대해서 알아 보자.
옵션자의 모태는 Read이다. 즉 파일을 읽고 '+' 연산자(모드)에 의해서 기능이 추가되었다. 즉 읽어짐을 바탕으로 하면서 원한다면 데이터를 수정할 수 있는 것이다!


그렇다! 'r+' 옵션을 사용한다면 파일내의 어떠한 위치의 값이라도 수정이 가능한 것이다. 위의 빨간 네모에서 보는 것처럼 원하는 데이터 값이 바뀌었음을 알 수 있다.

보통, 그냥 파일을 수정하라고 하면 "rw" 나 혹은 "a"를 사용해서 파일을 수정하려고 한다.
물론 'r+'를 하던 'w'를 하던 보통 프로그래밍을 할 때 중요한 것은 아니다. 그냥, 안되면 메모리에 올려서 다시 생성하면 되기 때문이다. 주변에서도 이런 것에 대해 당연 이 되는 것으로 알고 있지 직접 해본 사람이 드물며 아울러 그렇게 하는 사람도 별로 없기 때문이다. ( 아는 것과 직접 해본 경험과의 차이는 크다. )


Posted by k1rha