'공부합시다'에 해당되는 글 70건

  1. 2009.12.08 소스인사이트에서 탭을 space로 바꾸기
  2. 2009.12.07 소스인사이트 팁 총정리 4
  3. 2009.12.07 소스인사이트 팁5 : 오래된 창을 닫아주는 매크로
  4. 2009.12.07 소스인사이트 팁4 : 선택한 영역의 소스 비활성화 시키는 매크로
  5. 2009.12.07 소스인사이트 팁3 : if나 switch문의 뼈대를 작성해주는 매크로
  6. 2009.12.07 소스인사이트 팁2 : 소스와 같은 이름의 헤더파일을 여는 매크로
  7. 2009.12.07 소스인사이트 팁1 : 매크로를 이용한 한글 주석
  8. 2009.11.03 STST와 LDST
  9. 2009.10.26 PE 파일 분석 3
  10. 2009.10.16 [Visual Studio] IE 8.0 업데이트 후 VS2005, VS2008 class wizard 스크립트 오류 해결방법
2009. 12. 8. 10:16

소스인사이트에서 탭을 space로 바꾸기

alt + t를 누름
1. Tab width를 4 로 설정
2. Expand tab을 enable로 설정
3. Auto Indent는 취향에 맡게 simple에 체크 둘다 해주는거...

tab --> space로 일괄 변경
1. 소스 전체 선택
2. alt+ e
3. special  --> tab --> space 누름

정해진 tab width만큼으로 모두 변경됨
2009. 12. 7. 17:41

소스인사이트 팁 총정리

출처 : http://andstudy.springnote.com/pages/3778703

0.개요

본 문서는 안드로이드 스터디 모임에서 소스 인사이트를 통해 소스 코드 드라이빙을 하는 데

필요한 기능을 정리한 것이다.

 

1.자주 쓰는 기능

 

1.1 프로젝트 내 특정 심볼을 검색할 때?

F7

 

1.2 심볼이 검색이 안되는 경우는?

프로젝트 전체 파일들에 대해 lookup reference 기능을 이용해서 찾는다.(grep 명령어와 비슷)

ctrl + /

 

1.3 특정 단어(심볼)을 하이라이트 해서 보고 싶을 때?

shift + F8

 

아래 그림은 'coldboot' 함수를 하이라이트 한 것임.

si2.jpg

 

2.소스인사이트 세팅

 

2.1 소스인사이트에서 ARM assembly language 추가하기

안드로이드 소스 중 일부는 arm 기반의 어셈블리 파일로 되어 있다.

소스 인사이트의 기본 설정은 arm assembly에 대한 언어 정보가 추가되어 있지 않으므로

사용자가 별도로 추가해줘야 한다.

http://kaisyu.springnote.com/pages/1578764

 

2.2 소스인사이트 한글 주석 깨지는 걸 막는 매크로

인터넷 검색중 가장 깔끔한 방식인 듯 싶네요.

굳이 대화 상자 없이도 바로 입력 가능하게 하다니.. (정말 이 친구 아이디어 죽이네요 ^^)

출처 : http://blog.daum.net/bluebread

 

1. DoNoting() 이라는 macro를 만들어 추가한다. 진짜로 아무일도 하지 않는 걸로.
    macro DoNothing()
    {
    }
2. Option > Key Assignment 을 선택한다.
3. Macro: DoNothing 선택후에 Assign New Key를 누르고 다음의 키조합을 입력한다.
    Shift + 한/영 (황당한 조합이지만 먹힌다.)
4. 화면에 "shift+ " 로 표시되면 들어간 것이다.
5. 완료!!

이후로 아무 것도 해줄 필요가 없다.
그냥 메모장 쓰듯이 한글입력하면 된다. 쌍자음 그냥 입력해도 안 깨진다.

 

2.2 전체 file path를 보여주게끔 설정하기

소스 인사이트는 기본적으로 긴 파일 path를 ...으로 축약해서 보여준다.

소스 분석시 파일 경로를 제대로 아는 것은 매우 중요하다.

다음과 같은 설정으로 긴 파일 path를 정확하게 볼 수 있다.

 

si1.jpg

위의 그림과 같이 Trim long path names with ellipses 체크를 지우기.

 

2.3 떠 있는 창을 10개이내로 제한하기

http://www.ericstory.com/tag/Source%20Insight

 

 

3 단축키

1. Ctrl + = 또는 Ctrl + 왼쪽 마우스 버튼

=> 변수 및 함수에 커서를 위치시키고 이 키를 누르면 해당 선언문으로 이동 및 확인 할 수 있다.

 

2. Ctrl + 0

=> 우측 파일창으로 이동한다.

 

3. Alt + L

=> 좌측 함수창으로 이동한다.

 

4. F7 키

=> 프로젝트 전체에서 특정함수나 변수등을 찾기 위해 사용

 

5. F8 키

=> 현재 파일에서 특정함수나 변수등을 찾기 위해 사용

 

6. F5 키 (라인수 입력창)

=> 해당 라인으로 이동.

 

7. Alt + < or >

=> 이전/이후에 커서가 위치했던 곳으로 이동.

 

8. Ctrl + f, F3, F4

=> ctrl + f : 현재 파일 내에서 검색

   F3 : 이전 검색 부분 이동

   F4 : 다음 검색 부분 이동

 

9. Alt + 드래그

=> 블럭 단위로 선택.(라인 선택 아님)

 

10. Ctrl + L

=> 라인 번호 표시

 

11. Ctrl + M

=> bookmark

 

12. Ctrl + H

=> replace

 

Ctrl+W(or w): close the current file
Ctrl+Shift+W(or w) : close all the files
Ctrl+S(or s): save the current file
Ctrl+A(or a): save all the files
F3/F4: search backward/forward
Shift+F3/F4: search back/forward for the current word under cursor

 

Ctrl + =
해당심볼의 선언부로 이동한다. 사용함수,변수의 선언부로 이동시 편리

Ctrl + /
해당심볼로 프로젝트 전체범위로 검색

Shift + F9
검색결과에서 다음검색으로 이동한다.

Ctrl + ,
이전편집장소로 이동

F7
프로젝트 내 심볼 검색 및 이동

F8
파일 내 심볼 검색 및 이동

Shift + F8
파일심볼창 보이기/숨기기


2009. 12. 7. 16:58

소스인사이트 팁5 : 오래된 창을 닫아주는 매크로

이매크로는 아래의 코드중에 4라고 세팅된 수만큼의 코드윈도우를 제외하고 모두 닫아 버리는 기능을 합니다.

수천개의 소스를 탐색하고 돌아다니다 보면 자신도 모르게 많은 창을 띄우게 되는데 이중에 가장 최근에 보았던
창을 제외 하고 모두 닫아 버리는 센스 입니다.


/*
// Closes all but the most recently visited windows and files.
// Any dirty files are kept open.
*/
macro CloseOldWindows()
{
var hwnd
var cWnd

// This is the number of recent windows to keep open. You may change
// this constant to suit your needs.
var NumberOfWindowsToKeep; NumberOfWindowsToKeep = 4

hwnd = GetCurrentWnd()
cWnd = 0

// skip the most recently visited windows in the z-order
while (hwnd != hNil && cWnd < NumberOfWindowsToKeep)
{
cWnd = cWnd + 1
hwnd = GetNextWnd(hwnd)
}

// close the remaining windows
while (hwnd != hNil)
{
var hwndNext

hwndNext = GetNextWnd(hwnd)

// only close the window if the file is not edited
if (!IsBufDirty(GetWndBuf(hwnd)))
CloseWnd(hwnd)

hwnd = hwndNext
}

// close all files that are not visible in a window anymore
var cBuf
cBuf = BufListCount()
while (cBuf > 0)
{
var hbuf
cBuf = cBuf - 1
hbuf = BufListItem(cBuf)
if (GetWndHandle(hbuf) == hNil)
CloseBuf(hbuf)
}
}
2009. 12. 7. 16:56

소스인사이트 팁4 : 선택한 영역의 소스 비활성화 시키는 매크로

#if 0 ~ #endif로 
코드를 비활성 시키는 동작을 하게 합니다.

편집시 선택을 한부분에서 키동작으로 이매크로를 실행 시키면 그부분의 아래위가 #if 0 ~ #endif로
작성되어 코드를 비활성 시킵니다.


/*====================================================================
Create by sparrow
Unused Code Block
#if 0
unused code
#endif
====================================================================*/

macro UnUsedCodeBlock()
{
hbuf = GetCurrentBuf();
hwnd = GetCurrentWnd();

sel = GetWndSel(hwnd);

iLine = sel.lnFirst;
iLineEnd = sel.LnLast

InsBufLine(hbuf,iLine, "#if 0")
InsBufLine(hbuf,iLineEnd+2, "#endif")

}
2009. 12. 7. 16:53

소스인사이트 팁3 : if나 switch문의 뼈대를 작성해주는 매크로

아래의 매크로 역시 C++빌더 의 Ctrl + J 키를 흉내낸것입니다.
if 나 switch등의 자주 이용하는 키워드의 뼈대를 작성해주는 코드입니다.



/*====================================================================
Create by sparrow
Ctrl + J (C++Builder Code Generation function.
====================================================================*/



macro CodeCompletation()
{
hbuf = GetCurrentBuf()
ln = GetBufLnCur(hbuf)

line = GetBufLine(hbuf,ln)

DelBufLine(hbuf, ln)

if(strlen(line) <2)
{
return
}


cch = strlen(line)
ich = 0
space_cnt = 0
chTab = CharFromAscii(9)
szSpace = ""

while(ich <= cch)
{
ch = line[ich];
if (ch == " " || ch == chTab)
{
space_cnt = space_cnt + 1
}
else
{
szSpace = strmid(line,0,space_cnt)
line = strmid(line,space_cnt,strlen(line))
break
}
ich = ich + 1
}





if ( line == "if")
{
/* code completation if ~ else */


InsBufLine(hbuf, ln +0, "@szSpace@if( )")
InsBufLine(hbuf, ln +1, "@szSpace@{")
InsBufLine(hbuf, ln +2, "@szSpace@ ")
InsBufLine(hbuf, ln +3, "@szSpace@}")
InsBufLine(hbuf, ln +4, "@szSpace@else")
InsBufLine(hbuf, ln +5, "@szSpace@{")
InsBufLine(hbuf, ln +6, "@szSpace@ ")
InsBufLine(hbuf, ln +7, "@szSpace@}")
SetBufIns(hbuf,ln + 0,space_cnt + 3)
}
if (line == "ife")
{
/* code completation if ~ else */
InsBufLine(hbuf, ln +0, "@szSpace@if( )")
InsBufLine(hbuf, ln +1, "@szSpace@{")
InsBufLine(hbuf, ln +2, "@szSpace@ ")
InsBufLine(hbuf, ln +3, "@szSpace@}")
InsBufLine(hbuf, ln +4, "@szSpace@else if( )")
InsBufLine(hbuf, ln +5, "@szSpace@{")
InsBufLine(hbuf, ln +6, "@szSpace@ ")
InsBufLine(hbuf, ln +7, "@szSpace@}")
InsBufLine(hbuf, ln +8, "@szSpace@else")
InsBufLine(hbuf, ln +9, "@szSpace@{")
InsBufLine(hbuf, ln +10, "@szSpace@ ")
InsBufLine(hbuf, ln +11, "@szSpace@}")

SetBufIns(hbuf,ln + 0,space_cnt + 3)
}

else if(line == "do")
{
/* code completation do ~ while */
InsBufLine(hbuf, ln +0, "@szSpace@do")
InsBufLine(hbuf, ln +1, "@szSpace@{")
InsBufLine(hbuf, ln +2, "@szSpace@ ")
InsBufLine(hbuf, ln +3, "@szSpace@}while( )")
SetBufIns(hbuf,ln + 3,space_cnt +7)

}
else if (line == "while")
{
/* code completation if ~ else */
InsBufLine(hbuf, ln +0, "@szSpace@while( )")
InsBufLine(hbuf, ln +1, "@szSpace@{")
InsBufLine(hbuf, ln +2, "@szSpace@ ")
InsBufLine(hbuf, ln +3, "@szSpace@}")
SetBufIns(hbuf,ln + 0,space_cnt +6)

}
else if(line == "enum")
{
/* code completation enum ~ */
InsBufLine(hbuf, ln +0, "@szSpace@typedef enum")
InsBufLine(hbuf, ln +1, "@szSpace@{")
InsBufLine(hbuf, ln +2, "@szSpace@};")
SetBufIns(hbuf,ln + 2,space_cnt +1)

}
else if (line == "struct")
{
/* code completation struct ~ */
InsBufLine(hbuf, ln +0, "@szSpace@typedef struct")
InsBufLine(hbuf, ln +1, "@szSpace@{")
InsBufLine(hbuf, ln +2, "@szSpace@};")
SetBufIns(hbuf,ln + 2,space_cnt +1)

}
else if (line == "union")
{
/* code completation struct ~ */
InsBufLine(hbuf, ln +0, "@szSpace@union")
InsBufLine(hbuf, ln +1, "@szSpace@{")
InsBufLine(hbuf, ln +2, "@szSpace@};")
SetBufIns(hbuf,ln + 2,space_cnt +1)

}

else if(line == "switch")
{
/* code completation if ~ else */
InsBufLine(hbuf, ln +0, "@szSpace@switch( )")
InsBufLine(hbuf, ln +1, "@szSpace@{")
InsBufLine(hbuf, ln +2, "@szSpace@ case : ;")
InsBufLine(hbuf, ln +3, "@szSpace@ break;")
InsBufLine(hbuf, ln +4, "@szSpace@ case : ;")
InsBufLine(hbuf, ln +5, "@szSpace@ break;")
InsBufLine(hbuf, ln +6, "@szSpace@ case : ;")
InsBufLine(hbuf, ln +7, "@szSpace@ break;")
InsBufLine(hbuf, ln +8, "@szSpace@ case : ;")
InsBufLine(hbuf, ln +9, "@szSpace@ break;")
InsBufLine(hbuf, ln +10, "@szSpace@ default: ;")
InsBufLine(hbuf, ln +11, "@szSpace@}")
SetBufIns(hbuf,ln + 0,space_cnt +7)

}
else if(line == "for")
{
/* code completation if ~ else */
InsBufLine(hbuf, ln +0, "@szSpace@for( ; ; )")
InsBufLine(hbuf, ln +1, "@szSpace@{")
InsBufLine(hbuf, ln +2, "@szSpace@ ")
InsBufLine(hbuf, ln +3, "@szSpace@}")
SetBufIns(hbuf,ln + 0,space_cnt +4)

}
else if(line == "#ifdef")
{
/* code completation if ~ else */
InsBufLine(hbuf, ln +0, "#ifdef")
InsBufLine(hbuf, ln +1, "")
InsBufLine(hbuf, ln +2, "#else ")
InsBufLine(hbuf, ln +3, "")
InsBufLine(hbuf, ln +4, "#endif /* */")
SetBufIns(hbuf,ln + 0,space_cnt +7)

}
else if(line == "#ifndef")
{
/* code completation if ~ else */
InsBufLine(hbuf, ln +0, "#ifndef")
InsBufLine(hbuf, ln +1, "")
InsBufLine(hbuf, ln +2, "#else ")
InsBufLine(hbuf, ln +3, "")
InsBufLine(hbuf, ln +4, "#endif /* */")
SetBufIns(hbuf,ln + 0,space_cnt +8)

}
else if(line == "#if")
{
/* code completation if ~ else */
InsBufLine(hbuf, ln +0, "#if")
InsBufLine(hbuf, ln +1, "")
InsBufLine(hbuf, ln +2, "#else ")
InsBufLine(hbuf, ln +3, "")
InsBufLine(hbuf, ln +4, "#endif /* */")
SetBufIns(hbuf,ln + 0,space_cnt +4)

}


}
2009. 12. 7. 16:50

소스인사이트 팁2 : 소스와 같은 이름의 헤더파일을 여는 매크로

아래의 매크로는 C/ C++ 소스를 보는 중 같은 이름의 헤더 파일을 열도록 하는 매크로 입니다.

C++빌더 의 경우 F6키와 같은 동작을 합니다.
이러한 매크로를 작성 하기 위해서는 도움말의 매크로 랭귀지를 살작 참조해가면서 작성하고
매크로 .em파일을 base프로젝트에 추가하여 작성한다음

Option -> Preference -> Symbol Lookups 페이지에 Project symbol path에 base프로젝트를 추가해주고
Menu나 Key Assign으로 해두면 이용 할수 있습니다.

/*====================================================================
Create by sparrow 2005.09.30

Open C Source or Header file.

===================================================================*/
macro OpenSourceHeader()
{
hbuf = GetCurrentBuf()

bufFileName = tolower(GetBufName(hbuf))
pos = strlen(bufFileName)-1
while(bufFileName[pos] != ".")
pos = pos -1

szFileNameOnly = strmid(bufFileName,0,pos)

szFileExt = strmid(bufFileName, pos + 1, strlen(bufFileName))

if (szFileExt =="c" || szFileExt=="cpp" || szFileExt=="cxx" )
{
openbufFileName = cat(szFileNameOnly , ".h")

hopenbuf = OpenBuf(openbufFileName)
if (hopenbuf == hNil)
{
openbufFileName = cat(szFileNameOnly , ".hpp")
hopenbuf = OpenBuf(openbufFileName)
}

if (hopenbuf == hNil)
{
openbufFileName = cat(szFileNameOnly , ".hxx")
hopenbuf = OpenBuf(openbufFileName)
}

if (hopenbuf == hNil)
{
Msg("Cannot Open header file!")
return
}

SetCurrentBuf (hopenbuf)

}
else if (szFileExt=="h" || szFileExt=="hpp" || szFileExt=="hxx")
{

openbufFileName = cat(szFileNameOnly , ".c")

hopenbuf = OpenBuf(openbufFileName)
if (hopenbuf == hNil)
{
openbufFileName = cat(szFileNameOnly , ".cpp")
hopenbuf = OpenBuf(openbufFileName)
}

if (hopenbuf == hNil)
{
openbufFileName = cat(szFileNameOnly , ".cxxx")
hopenbuf = OpenBuf(openbufFileName)
}


if (hopenbuf == hNil)
{
Msg("Cannot Open source file!")
return
}

SetCurrentBuf (hopenbuf)


}

}
2009. 12. 7. 16:41

소스인사이트 팁1 : 매크로를 이용한 한글 주석

소스 인사이트 사용시 가장 불편한 점은 한글 입력이 제대로 되지 않는 다는 점이다. 이것은 유니코드 입력을 지원하지 않아 생기는 문제인데, 보통은 쌍자음의 입력시 커서를 앞으로 하나 옮겨 del키로 한번 삭제하여 수정이 가능하다. 다만 이 방법은 무지 귀찮은데 이것을 좀 더 편하게 해결할 수 있는 방법을 찾다가 아래와 같은 포스팅을 찾게 되었다.

원문  : Sourceinsight(소스인사이트) 에서 한글 주석 입력하기. -매크로이용 첫번째



먼저  위에 링크된 파일을  My Documents\Source Insight\Projects\Base 에 다운받습니다.

소스인사이트를 열고 base 프로젝트를 열어서

다운받은 파일을 프로젝트에 추가합니다. (중요~)

(보시면 아시겠지만 hangulcmt 함수 달랑 하나 들어있습니다.;)


 위에를 다 하셨으면 다음


사용자 삽입 이미지

option의 key assignment 로 들어가셔서




사용자 삽입 이미지

그림처럼 매크로 커맨드를 찾습니다. command 창에 macro를 입력하면 입력하기도 전에 찾습니다.;


그후에 그림과 같이 hangulcmt 를 선택한후 원하는 키를 지정하시면 됩니다.

assign new key 를 누르면 되겠죠..

시험삼아 동작시키는화면이라 아무거나(ctrl+shft+T) 로 지정한 화면입니다.



여기까지 하시면 잘되리라 믿습니다.

만약에 만약에 안되시다면. 열내지 마시고 아래와 같이 해보세요~



사용자 삽입 이미지

옵션으로 들어가셔서~




사용자 삽입 이미지

symbol Lookups 탭에서.


사용자 삽입 이미지

add project to path 를 누르신후 베이스 프로켁트를 선택합니다.

=======================================================================================================

공식 매크로 사이트 : http://www.sourceinsight.com/public/macros/
2009. 11. 3. 12:31

STST와 LDST

STST 와 LDST 구현하기

file : main.c
typedef struct _Context
{

    int   efl;
    int   eip;
    int   edi;
    int   esi;
    int   ebp;
    int   esp;
    int   ebx;
    int   edx;
    int   ecx;
    int   eax;
}Context;

void LDST(Context *);
void STST(Context *);

int main()
{
    Context stat;
    int i;
    memset(&stat, 0,sizeof(Context));
    printf("시작\n");
    printf("efl = [%08X]\n", stat.efl);
    printf("eip = [%08X]\n", stat.eip);
    printf("edi = [%08X]\n", stat.edi);
    printf("esi = [%08X]\n", stat.esi);
    printf("ebp = [%08X]\n", stat.ebp);
    printf("esp = [%08X]\n", stat.esp);
    printf("ebx = [%08X]\n", stat.ebx);
    printf("edx = [%08X]\n", stat.edx); 
    printf("ecx = [%08X]\n", stat.ecx);
    printf("eax = [%08X]\n", stat.eax); 

    STST(&stat);

    printf("\n");
    printf("여기는 과거\n");

    printf("efl = [%08X]\n", stat.efl);
    printf("eip = [%08X]\n", stat.eip);
    printf("edi = [%08X]\n", stat.edi);
    printf("esi = [%08X]\n", stat.esi);
    printf("ebp = [%08X]\n", stat.ebp);
    printf("esp = [%08X]\n", stat.esp);
    printf("ebx = [%08X]\n", stat.ebx);
    printf("edx = [%08X]\n", stat.edx); 
    printf("ecx = [%08X]\n", stat.ecx);
    printf("eax = [%08X]\n", stat.eax); 

    printf("0 == Exit, 1 == First\n");
    scanf("%d", &i);

    if(1 == i)
    {
        LDST(&stat);
        printf("실패!!!");
    }

    return 0;


file : asm.asm

segment .text
    global    _STST
    global    _LDST

_STST:
    push     ebp
    mov     ebp, esp

    pushf
    mov    esp, [ebp+8]    ;context 의 시작 주소
    add    esp, 40        ;context 의 끝 주소
    pusha        ; ax, cx, dx, bx, sp, bp, si, di

    mov    eax, [ebp+4]    ;eax = eip(return address)
    push    eax        ;context.eip = eip

    mov    eax, [ebp-4]    ;eax = efl
    push    eax        ;context.efl = efl
    mov    eax, [ebp]    ;eax = before ebp
    mov    [esp+16], eax    ;context.ebp = ebp(before)
    mov    eax, ebp   
    add    eax, 8        ;eax = before esp
    mov    [esp+20], eax    ;context.esp = esp(before)

    mov     esp, ebp
    pop     ebp

    ret

_LDST:
    mov    esp, [esp+4]    ;esp = address of context
    popf                ;efl = context.efl

    pop    eax            ;eax = context.eip
    mov    ebx, esp        ;ebx = esp
    mov    esp, [esp+12]    ;esp = context.esp
    push     eax            ;esp(before) = eip

    mov    esp, ebx        ;esp(before) = esp(now)

    popa                ;di, si, bp, bx, dx, cx, ax

    mov    esp, [esp-20]    ;esp = context.esp(before)
    sub    esp, 4        ;esp(before) = eip(before)

    ret

2009. 10. 26. 12:22

PE 파일 분석

0. 들어가기에 앞서

PE 포맷을 분석하기에 앞서 먼저 PE 포맷이란게 무엇인지 알아볼 필요가 있다. PE 포맷을 위키에서 검색하면 다음과 같이 나온다.

PE 포맷(Portable Excutable)은 마이크로소프트윈도 3.1부터 지원되는 실행 파일형식을 말한다. 유닉스 COFF(영어: Common Object file format)를 기반으로 나왔으며, PE 포맷을 사용하는 파일의 확장자는 cpl, exe, dll, ocx, vxd, sys, scr, drv가 있다.

다양한 운영 체제에서의 이식성을 보여준다는 뜻에서 이식이 가능한 실행 형식(영어: Portable Excutable)이라는 이름이 붙었다.

PE 형식은 근본적으로 윈도 OS 로더가 감춰진 실행 코드를 다루는 데 있어서 필수적인 정보를 은닉해 주는 자료 구조이다. 이것은 링크와 API 내보내기/가져오기 테이블, 리소스 관리 데이터, 스레드 로컬 장치 데이터들을 포함하는 동적 라이브러리를 포함한다. 확장 펌웨어 인터페이스(EFI)는 EFI 환경에서의 표준 실행 PE 포맷이다.


... 뭐 충분한 설명이 되었다고 생각한다.


1. PE 파일 포맷의 전체 구조
(출처 : http://kkamagui.springnote.com/pages/401262)


붉은 색 부분은 헤더나 데이터가 위치하는 영역의 속성과 크기 등등을 나타내는 정보이고, 푸른 색 부분은 실제 데이터들이 위치하는 영역을 나타낸다.

  • IMAGE_DOS_HEADER : PE 파일의 처음에 위치하며 뒷부분에 DOS에서 실행했을 때,  에러 메시지(This program cannot be run in DOS mode)를 표시하는 스텁(Stub) 코드를 포함하고 있음. MAGIC Number와 다음에 오는 IMAGE_NT_HEADER의 위치를 표시
  • IMAGE_NT_HEADER : PE 파일 포맷에 대한 정보를 포함. 아래의 두 부분으로 구성
    • IMAGE_FILE_HEADER :  Section의 수 및 속성과 같은 정보 포함
    • IMAGE_OPTIONAL_HEADER : PE 파일에 대한 속성 또는 이미지 베이스와 같은 정보 포함
      • Data Directory : 어떤 영역의 Virtual Address와 Size 정보를 포함
  • IMAGE_SECTION_HEADER : 섹션에 대한 실질적인 정보를 포함
  • Section(섹션) : 실제 데이터가 위치하는 영역

각 영역에 대해 세부적으로 알아보자.


2. IMAGE_DOS_HEADER


이 구조체에서 중요한 부분은 실행파일인지 판단하기 위한 e_magic (MZ로 셋팅) 부분과 다음에 오는 IMAGE_NT_HEADER의 위치를 표시해 주는 e_lfanew 부분이다.


3. IMAGE_NT_HEADER


IMAGE_NT_HEADER는 실제 PE 파일 포맷에 대한 정보를 포함하는 헤더로써 IMAGE_FILE_HEADER와 IMAGE_OPTIONAL_HEADER로 구성된다. Signature는 IMAGE_NT_SIGNATURE 로 <PE00>의 값을 가진다.


4. IMAGE_FILE_HEADER


  • Machine : CPU ID를 나타내는데, 간단히 보면 Intel 인지, MIPS 인지 등등의 정보가 들어있음
  • NumberOfSections : PE 파일에 포함된 총 섹션의 수를 나타냄
  • TimeDateStamp : 컴파일러 또는 링커가 파일을 생성한 시간. 1970년 1월 1일 GMT 기준으로 지나온 초
  • PointerToSymbolTable :  COFF 파일의 심볼 테이블의 오프셋을 나타냄. 없는 경우가 대부분
  • NumberOfSymbols : 심볼의 개수를 나타냄
  • SizeOfOptionalHeader : 뒤에 이어서 나오는 Optional Header의 크기를 나타낸다. 32Bit/64Bit에 따라서 그 크기가 다름
  • Characteristics : 파일의 특성

Machine에 대한 define 값들은 WinNT.h에 정의 되어있다.


Characteristics에 대한 define 값 역시 WinNT.h에 정의 되어있다.



5. IMAGE_OPTIONAL_HEADER


Optional Header는 PE 파일의 전반적인 내용들에 대한 정보를 포함한다. 중요한 정보만 추리면 다음과 같다.
  • Magic : Signature로 32Bit의 경우 0x10b를 가짐
  • SizeOfCode : 섹션 중에 IMAGE_SCN_CNT_CODE 속성을 가진 섹션들 전체의 합
  • SizeOfInitializedData : 섹션 중에 IMAGE_SCN_CNT_INITIALIZED_DATA 속성을 가진 섹션들 전체의 합
  • SizeOfUninitializedData : 섹션 중에 IMAGE_SCN_CNT_UNINITIALIZED_DATA 속성을 가진 섹션들 전체의 합
  • AddressOfEntryPoint : Entry Point의 주소. 실제 로더가 제일 먼저 실행할 코드의 시작점
  • BaseOfCode : 코드가 시작되는 상대 주소(RVA)
  • BaseOfData : 데이터가 시작되는 상대 주소(RVA)
  • ImageBase : 이미지가 로딩되는 메모리의 Base 주소. 일반적으로 실행파일의 경우 0x400000(4Mbyte) 위치에 로딩
  • SectionAlignment : 섹션이 정렬되는 크기. PE 파일 자체가 메모리 맵 파일이기 때문에 0x1000(4Kbyte) 보다 크거나 같아야 함
  • SizeOfImage : 모든 섹션들의 합. 이미지 실행을 위해 메모리를 할당해야 하는 총 크기
  • NumberOfRvaAndSizes : 뒤에 오는 DataDirectory의 개수. 무조건 16개
  • Data Directory : 총 16개가 있으며 각 항목은 특정 데이터에 대한 정보를 가지고 있음. 뒤에서 설명

6. IMAGE_DATA_DIRECTORY


 데이터 디렉토리는 위와 같은 구조로 이루어져있으며 IMAGE_OPTIONAL_HEADER에 총 16개가 있다. 각각에 Index에 대한 define 값은 WinNT.h에 아래와 같이 정의되어있다.

 이미지 디렉토리 정보는 굉장히 중요하다. 경우에 따라서 섹션이 합쳐질 수 있기 때문에 통합된 섹션에서 원하는 정보를 찾는 방법은 이미지 디렉토리에 포함된 정보를 이용하는 방법 밖에는 없다. 여러모로 많이 쓰이는 인덱스는 아래와 같은 역할을 한다.

  • IMAGE_DIRECTORY_ENTRY_EXPORT : Export 함수들에 대한 Export Table의 시작 위치와 크기를 나타냄
  • IMAGE_DIRECTORY_ENTRY_IMPORT : Import 함수들에 대한 Import Table의 시작 위치와 크기를 나타냄
  • IMAGE_DIRECTORY_ENTRY_RESOURCE : IMAGE_RESOURCE_DIRECTORY 구조체의 시작 위치를 나타냄
  • IMAGE_DIRECTORY_ENTRY_TLS : Thread Local Storage에 대한 포인터
  • IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG : IMAGE_LOAD_CONFIG_DIRECTORY 구조체애 대한 포인터
  • IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT : IMAGE_BOUND_IMPORT_DESCRIPTOR 구조체의 배열을 가리키는 포인터
  • IMAGE_DIRECTORY_ENTRY_IAT : Import Address Table의 시작 위치를 나타냄
 실제 위의 값중에서 변경하면 OS의 로더에 의해 로딩이 되지 않는 부분이 있는데, 붉은 색으로 표시된 IMAGE_DIRECTORY_ENTRY_TLSIMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 부분이다. 이 부분은 미리 로더가 읽어서 초기 작업을 실행하는 부분이라 이부분이 포함된 영역을 이상하게 조작하게되면 로더가 로딩에 실패하게 된다.


7. IMAGE_SECTION_HEADER

 PE 헤더의 뒷부분에 연속해서 IMAGE_SECTION_HEADER가 위치하게 된다. 섹션은 뒤에 올 코드나 데이터가 위치하는 영역에 대한 구체적인 정보를 포함하고 있으므로 굉장히 중요하다.
 섹션의 개수는 앞서 IMAGE_FILE_HEADER에 포함된 NumberOfSections에서 얻을 수 있으며 해당 개수만큼 얻어오면 된다. IMAGE_SECTION_HEADER는 WinNT.h에 아래와 같이 정의되어있다.


중요한 항목에 대한 의미는 아래와 같다.
  • VirtualSize : 실제 코드나 데이터 영역의 크기를 표시
  • VirtualAddress : 메모리에 로드되었을 때 RVA를 표시
  • SizeOfRawData : VirtualSize의 크기를 IMAGE_OPTIONAL_HEADER에 포함된 FileAlignment의 단위로 올림한 크기
  • PointerToRawData : 실제 섹션 데이터가 파일 내에 존재하는 오프셋. Virtual Address와 같을 수도 있고 다를 수도 있음
  • Characteristics : 섹션의 속성 표시. 자세한 것은 뒤를 참조

 위의 VirtualSize와 SizeOfRawData는 영역의 크기를 나타낸다는 공통점이 있으나 라운드 업된 크기와 실제 크기를 나타낸다는 차이가 있다. 만약 섹션의 크기를 조작했다면 위의 두부분 모두 손을 봐야 한다.

 Virtual Address와 Pointer To Raw Data의 값이 다를 수 있다고 했는데, 왜그럴까? 이것은 실행 파일의 크기를 줄이기 위해서이다. 만약 로드 되었을 때 크기가 0x2000 정도인 섹션이 있다고 하자. 그런데 이 섹션은 메모리의 값이 초기화 될 필요도 없고 값도 들어있지 않다면? 실행 시에 영역만 할당해주면 끝이라면? 이런 경우라면 굳이 이 섹션이 실행파일에서 영역을 가지고 있을 필요가 없다. 따라서 Virtual Address는 0이 아닌 값을 갖겠지만 파일 내에 위치를 의미하는 Pointer To Raw Data의 값은 0이 된다.

 즉 실제 파일 내에는 존재하지 않는 영역이 생김으로써 Virtual Address와 Pointer To Raw Data의 값이 달라질 수 있으며, 기타 다른 이유로도 충분히 다를 수 있다. 따라서 실행파일을 조작하기위해서는 Pointer To Raw Data의 값을 위주로 작업을 해야 한다.

 

 Characteristics는 해당 영역의 속성을 나타내는데, WinNT.h에 정의되어있고 아주 흥미로운 값을 가지고 있다.

//
// Section characteristics.
//
//      IMAGE_SCN_TYPE_REG                   0x00000000  // Reserved.
//      IMAGE_SCN_TYPE_DSECT                 0x00000001  // Reserved.
//      IMAGE_SCN_TYPE_NOLOAD                0x00000002  // Reserved.
//      IMAGE_SCN_TYPE_GROUP                 0x00000004  // Reserved.
#define IMAGE_SCN_TYPE_NO_PAD                0x00000008  // Reserved.
//      IMAGE_SCN_TYPE_COPY                  0x00000010  // Reserved.

#define IMAGE_SCN_CNT_CODE                   0x00000020  // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA       0x00000040  // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA     0x00000080  // Section contains uninitialized data.

#define IMAGE_SCN_LNK_OTHER                  0x00000100  // Reserved.
#define IMAGE_SCN_LNK_INFO                   0x00000200  // Section contains comments or some other type of information.
//      IMAGE_SCN_TYPE_OVER                  0x00000400  // Reserved.
#define IMAGE_SCN_LNK_REMOVE                 0x00000800  // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT                 0x00001000  // Section contents comdat.
//                                           0x00002000  // Reserved.
//      IMAGE_SCN_MEM_PROTECTED - Obsolete   0x00004000
#define IMAGE_SCN_NO_DEFER_SPEC_EXC          0x00004000  // Reset speculative exceptions handling bits in the TLB entries for this section.
#define IMAGE_SCN_GPREL                      0x00008000  // Section content can be accessed relative to GP
#define IMAGE_SCN_MEM_FARDATA                0x00008000
//      IMAGE_SCN_MEM_SYSHEAP  - Obsolete    0x00010000
#define IMAGE_SCN_MEM_PURGEABLE              0x00020000
#define IMAGE_SCN_MEM_16BIT                  0x00020000
#define IMAGE_SCN_MEM_LOCKED                 0x00040000
#define IMAGE_SCN_MEM_PRELOAD                0x00080000

#define IMAGE_SCN_ALIGN_1BYTES               0x00100000  //
#define IMAGE_SCN_ALIGN_2BYTES               0x00200000  //
#define IMAGE_SCN_ALIGN_4BYTES               0x00300000  //
#define IMAGE_SCN_ALIGN_8BYTES               0x00400000  //
#define IMAGE_SCN_ALIGN_16BYTES              0x00500000  // Default alignment if no others are specified.
#define IMAGE_SCN_ALIGN_32BYTES              0x00600000  //
#define IMAGE_SCN_ALIGN_64BYTES              0x00700000  //
#define IMAGE_SCN_ALIGN_128BYTES             0x00800000  //
#define IMAGE_SCN_ALIGN_256BYTES             0x00900000  //
#define IMAGE_SCN_ALIGN_512BYTES             0x00A00000  //
#define IMAGE_SCN_ALIGN_1024BYTES            0x00B00000  //
#define IMAGE_SCN_ALIGN_2048BYTES            0x00C00000  //
#define IMAGE_SCN_ALIGN_4096BYTES            0x00D00000  //
#define IMAGE_SCN_ALIGN_8192BYTES            0x00E00000  //
// Unused                                    0x00F00000

#define IMAGE_SCN_LNK_NRELOC_OVFL            0x01000000  // Section contains extended relocations.
#define IMAGE_SCN_MEM_DISCARDABLE            0x02000000  // Section can be discarded.
#define IMAGE_SCN_MEM_NOT_CACHED             0x04000000  // Section is not cachable.
#define IMAGE_SCN_MEM_NOT_PAGED              0x08000000  // Section is not pageable.
#define IMAGE_SCN_MEM_SHARED                 0x10000000  // Section is shareable.
#define IMAGE_SCN_MEM_EXECUTE                0x20000000  // Section is executable.
#define IMAGE_SCN_MEM_READ                   0x40000000  // Section is readable.
#define IMAGE_SCN_MEM_WRITE                  0x80000000  // Section is writeable.

 

  중요한 플래그 별로 의미를 보면 아래와 같다.

  • IMAGE_SCN_CNT_CODE : 섹션에 코드가 포함되어있음. IMAGE_SCN_MEM_EXECUTE와 보통 같이 지정됨
  • IMAGE_SCN_CNT_INITIALIZED_DATA : 섹션이 초기화된 데이터를 포함하고 있음
  • IMAGE_SCN_CNT_UNINITIALIZED_DATA : 섹션이 초기화 되지 않은 데이터를 포함하고 있음
  • IMAGE_SCN_MEM_DISCARDABLE : 섹션이 버려질 수 있음. 한번 사용되고 필요없는 섹션들(relocation 데이터 같은 경우)이 이 속성을 가짐
  • IMAGE_SCN_MEM_SHARED : 섹션이 이 모듈을 사용하는 모든 프로세스에 의해서 공유될 수 있음을 의미
  • IMAGE_SCN_MEM_EXECUTE : 섹션이 실행 가능함
  • IMAGE_SCN_MEM_READ : 섹션이 읽기 가능함
  • IMAGE_SCN_MEM_WRITE : 섹션이 쓰기 가능함

 위 의 값을 보면 섹션에 대한 속성이 미리 정의되어있다는 것을 알 수 있다. 즉 데이터 섹션 같은 경우 IMAGE_SCN_MEM_READ/WRITE 속성을 가지고 있으리라 유추할 수 있고, 코드가 포함된 섹션의 경우 IMAGE_SCN_MEM_EXECUTE 속성을 가지고 있다고 유추할 수 있다.

 섹션의 경우 섹션 이름을 가지고 있는데, VC로 실행파일을 만들면 .text, .data, .idata와 같은 이름의 섹션들이 생긴다. 이름 그대로 코드, 데이터와 같은 정보가 포함된 섹션이라는 것을 알 수 있는데, 여기서 속지 말아야 할 것은 섹션 이름은 권장값이므로 섹션 이름으로 섹션이 포함하는 내용을 판단하면 안된다는 것이다. 특히 파일의 크기를 줄이는 릴리즈 옵션 같은 경우는 섹션들이 합쳐져서 하나의 섹션으로 존재하는 경우도 있기 때문에 섹션 이름을 이용해서 찾아서는 안되며 IMAGE_NT_HEADER에 있는 Data Directory의 값을 참조해서 찾도록 해야 한다.

=======================================================================================================

출처 : kkamagui의 프로그래밍 작업실 http://kkamagui.springnote.com/pages/401262


......처음에는 정리하면서 배끼다가 결국 뒤에는 ctrl+c, ctrl+v -ㅅ-;;

'공부합시다 > 파일 포맷' 카테고리의 다른 글

ID3v2 분석  (0) 2009.10.09
ID3v2 Frame ID List  (0) 2009.10.08
MP3 ID3 tag 분석  (0) 2009.10.08
2009. 10. 16. 14:50

[Visual Studio] IE 8.0 업데이트 후 VS2005, VS2008 class wizard 스크립트 오류 해결방법

1. regedit 실행
2. "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones" 항목에 "1000"키 생성
3. "1000"키 항목에 DWORD값 추가
이름 : 1207
값    : 0x000000