'system/windows'에 해당되는 글 10건

  1. 2012.06.15 PE patch를 이용한 DLL loading
  2. 2012.03.06 가상 키 코드(스캔코드) 테이블
  3. 2012.02.24 쉽게 쓴 dll
  4. 2012.01.16 관리자 권한 실행 - UAC 고려하기
  5. 2011.10.31 Segmentation 시발점 찾다가
  6. 2011.09.01 110901 긁적긁적
  7. 2010.09.03 dll injection 기초
  8. 2010.08.05 win 명령어
  9. 2010.07.07 컬링 컨벤션 세가지(cdecl,stdcall,fastcall)
  10. 2010.07.06 메모리 관리와 함수

PE patch를 이용한 DLL loading

system/windows 2012. 6. 15. 11:28

널패딩영역 확인


널패딩영역 IDT 코드 덮어쓰기 후 실행 검증


reloc 헤더 계산

Size of Raw Data 와 Virtual Size 비교하여 사용가능한곳에 삽입

reloc 섹션이 시작하는 Pointer to Raw Data(file), RVA(Memory)


BOUNT IMPORT TABLE 제거 - NULL


IDT 호출 주소 변경, IDT 크기 업데이트


text 헤더 널패딩영역 확인 후 INT, Name, IAT 셋팅


이동한 IDT 영역에서 INT, Name, IAT 등의 호출 주소 삽입


text 헤더 영역 Characteristics 변경 - 쓰기 가능하도록 수정


실행 검증


'system > windows' 카테고리의 다른 글

가상 키 코드(스캔코드) 테이블  (0) 2012.03.06
쉽게 쓴 dll  (0) 2012.02.24
관리자 권한 실행 - UAC 고려하기  (0) 2012.01.16
Segmentation 시발점 찾다가  (0) 2011.10.31
110901 긁적긁적  (0) 2011.09.01
:

가상 키 코드(스캔코드) 테이블

system/windows 2012. 3. 6. 19:42

키코드 Value(HEX) Value(DEC)
VK_LBUTTON 01 1 마우스 왼쪽 버튼
VK_RBUTTON 02 2 마우스 오른쪽 버튼
VK_CANCEL 03 3 Ctrl + C
VK_MBUTTON 04 4 마우스 가운데 버튼
VK_BACK 08 8 Backspace 
VK_TAB 09 9 Tab
VK_CLEAR 0C 12 CLEAR
VK_RETURN 0D 13 Enter
VK_SHIFT 10 16 Shift
VK_CONTROL 11 17 Ctrl(좌측)
VK_MENU 12 18 Alt(좌측)
VK_PAUSE 13 19 Pause Break
VK_CAPITAL 14 20 Caps Lock
VK_HANGUL 15 21 한/영 키
VK_HANJA 19 25 한자 키
VK_ESCAPE 1B 27 ESC
VK_SPACE 20 32 Spacebar
VK_PRIOR 21 33 Page Up
VK_NEXT 22 34 Page Down
VK_END 23 35 End
VK_HOME 24 36 Home
VK_LEFT 25 37 Left Arrow(←)
VK_UP 26 38 Up Arrow(↑)
VK_RIGHT 27 39 Right Arrow(→)
VK_DOWN 28 40 Down Arrow(↓)
VK_SELECT 29 41 Select
VK_EXECUTE 2B 43 EXECUTE
VK_SNAPSHOT 2C 44 PrtScr
VK_INSERT 2D 45 Insert
VK_DELETE 2E 46 Delete
VK_HELP 2F 47 Help
VK_0 30 48 0 키
VK_1 31 49 1 키
VK_2 32 50 2 키
VK_3 33 51 3 키
VK_4 34 52 4 키
VK_5 35 53 5 키
VK_6 36 54 6 키
VK_7 37 55 7 키
VK_8 38 56 8 키
VK_9 39 57 9 키
VK_A 41 65 A 키
VK_B 42 66 B 키
VK_C 43 67 C 키
VK_D 44 68 D 키
VK_E 45 69 E 키
VK_F 46 70 F 키
VK_G 47 71 G 키
VK_H 48 72 H 키
VK_I 49 73 I 키
VK_J 4A 74 J 키
VK_K 4B 75 K 키
VK_L 4C 76 L 키
VK_M 4D 77 M 키
VK_N 4E 78 N 키
VK_O 4F 79 O 키
VK_P 50 80 P 키
VK_Q 51 81 Q 키
VK_R 52 82 R 키
VK_S 53 83 S 키
VK_T 54 84 T 키
VK_U 55 85 U 키
VK_V 56 86 V 키
VK_W 57 87 W 키
VK_X 58 88 X 키
VK_Y 59 89 Y 키
VK_Z 5A 90 Z 키
VK_LWIN 5B 91 윈도우키(좌측)
VK_RWIN 5C 92 윈도우키(우측)
VK_APPS 5D 93 App Menu 키
VK_NUMPAD0 60 96 숫자키패드 0
VK_NUMPAD1 61 97 숫자키패드 1
VK_NUMPAD2 62 98 숫자키패드 2
VK_NUMPAD3 63 99 숫자키패드 3
VK_NUMPAD4 64 100 숫자키패드 4
VK_NUMPAD5 65 101 숫자키패드 5
VK_NUMPAD6 66 102 숫자키패드 6
VK_NUMPAD7 67 103 숫자키패드 7
VK_NUMPAD8 68 104 숫자키패드 8
VK_NUMPAD9 69 105 숫자키패드 9
VK_MULTIPLY 6A 106 숫자키패드 *
VK_NUMADD 6B 107 숫자키패드 +
VK_SEPARATOR 6C 108 SEPARATOR
VK_SUBTRACT 6D 109 숫자키패드 -
VK_DECIMAL 6E 110 숫자키패드 .
VK_DEVIDE 6F 111 숫자키패드 /
VK_F1 70 112 F1 키
VK_F2 71 113 F2 키
VK_F3 72 114 F3 키
VK_F4 73 115 F4 키
VK_F5 74 116 F5 키
VK_F6 75 117 F6 키
VK_F7 76 118 F7 키
VK_F8 77 119 F8 키
VK_F9 78 120 F9 키
VK_F10 79 121 F10 키
VK_F11 7A 122 F11 키
VK_F12 7B 123 F12 키
VK_F13 7C 124 F13 키
VK_F14 7D 125 F14 키
VK_F15 7E 126 F15 키
VK_F16 7F 127 F16 키
VK_F17 80 128 F17 키
VK_F18 81 129 F18 키
VK_F19 82 130 F19 키
VK_F20 83 131 F20 키
VK_F21 84 132 F21 키
VK_F22 85 133 F22 키
VK_F23 86 134 F23 키
VK_F24 87 135 F24 키
VK_NUMLOCK 90 144 Num Lock 키
VK_SCROLL 91 145 Scroll Lock 키

'system > windows' 카테고리의 다른 글

PE patch를 이용한 DLL loading  (0) 2012.06.15
쉽게 쓴 dll  (0) 2012.02.24
관리자 권한 실행 - UAC 고려하기  (0) 2012.01.16
Segmentation 시발점 찾다가  (0) 2011.10.31
110901 긁적긁적  (0) 2011.09.01
:

쉽게 쓴 dll

system/windows 2012. 2. 24. 16:33

  • 기초부터 가자~ DLL 이란 무엇인가
 dll이란 무엇인가. 대부분 .dll파일을 한번씩은 본적이 있을 것이다. 
 이 dll 파일이란 실행파일이 요구되는 변수 함수등을 공유하기 위해 외부적으로 만든 라이브러리 라고 보면 된다.(이해하기를)
 공통 부분의 함수를 공유하기가 용이하기 때문에 자주 사용되는 변수나 함수등의 내용을 dll로 작성하여 개발 시간이 단축될 수 있다. (나는 보통 cpp, h 파일로 작성하여 필요할때마다 파일을 카피 하여 프로젝트에 추가하곤 한다. 하지만 이 방법을 쓸 경우 굳이 파일을 포함시키지 않더라도pragma나 비쥬얼 스튜디오의 프로젝트 속성에 dll 파일을 링크하여 가져다 쓸 수 있다.)


  • DLL, 어떻게 가져다 써?
에잉~  중간에 내용 추가하려니까 더 귀찮네-_-;
깜빡하고 넘어간 것. DLL을 만드는건 그렇다 치고 어떻게 가져다 쓸것인가?

이 부분은 자세하게 풀이된 글이 있어 가져왔다.(많은 도움이 되었다 감동)
http://blog.naver.com/kyehwan2?Redirect=Log&logNo=10005701934
 삽질 해결을 위해 너무너무 많은 도움이 된 글이고 굳이 사견을 덧붙일 필요없이 예제까지 정리가 깔끔히 된 글이라 그대로 가져왔다.

호출하는 방법은 implicit 과 explicit 방법이 있는데
우선 여기선 조금쉬운 방법인 implicit방법을 먼저 하자
위에서 DLL을 만들때 같이 만들어 지는 lib를 이용한다.
 
여기서 lib에 대해 언급하면...
링크될때 링커는 이 lib파일을 표준 라이브러리 처럼 다루어 처리하지만, dll을 끌어오는
lib파일은 dll이 익스포트한 함수 각각에 대한 stub(함수 호출에 쓰이는 정보를 일컬음)만을 포함
 
함수 스텁은 사실 진짜 함수와 동일한 이름과 인수 리스트를 가진 pseudo 함수로서,
내부를 살펴보면 스텁에 필요한 모든 인수를 넘겨서 DLL에 들어있는 진짜 함수를 호출하는
짤막한 코드가 들어있다.
이렇게하면 DLL의 함수를 분리된 파일이 아니라, 애플리케이션 코드의 일부인 것처럼
다루게 된다
 
LIB 파일을 임포트 라이브러리라고 부른다.

(1)Implict 링킹
 
“DLL이 있어서 DLL이 바로 동적 링크되는데 LIB 파일이 왜 필요한가?” 

이렇게 물어보는 사람도 있을 것입니다. 이유는 메인프로그램을 컴파일하고 링크할 때 DLL 안에 있는 함수들은 메인프로그램에는 어느 것과도 링크되어 있지 않아 실행 파일로 만들 때 에러가 나오기 때문입니다. 예를 들어, PaintImage(LPSTR  filename);이라는 함수를 DLL로 만들어 놓고 메인프로그램에서 헤더에 extern "C"__declspec(dllimport)void PaintImage(LPSTR filename);이라고 정의하면 컴파일은 하지만 링크할 때 PaintImage 함수를 찾을 수 없다고 하며 에러를 리턴하고 실행 파일을 만들 수 없게 됩니다. 따라서, PaintImage라는 함수를 가상으로 만들어 그것을 0으로 설정해 주는 하나의 함수가 있어야 합니다.
void PaintImage(LPSTR  fileanem)=0;
 이렇게 만들어진 함수가 컴파일되어 LIB로 만들어집니다. 따라서, 메인프로그램에서는 실행 내용이 아무것도 들어 있지 않은 LIB를 프로젝트에 삽입하고 컴파일하는 것이죠. 그런 후 프로그램이 실행되면 LIB에 설정된 파일명에 따라 DLL을 로드하고 프로그램 메모리 안에 DLL에서 로드시킨 PaintImage 모듈을 삽입시키게 됩니다. 결국 우리는 DLL을 만들고 난 후 3가지의 파일을 이용해서 메인프로그램을 제작하게 되는 것입니다. 이 3가지 파일은 다음과 같습니다. 

① 실질적으로 프로그램이 실행될 때 로드되는 DLL 파일(*.DLL) 
② 컴파일할 때 설정해 주는 함수명이 들어 있는 헤더 파일(*.H) 
③ 링크할 때 메인프로그램에 빈 함수를 설정하는 LIB 파일(*.LIB)

(2)Explicit 링킹 
 Explicit 링킹 방법이란 Implict 링킹 처럼 3가지의 파일이 필요가 없이 단순하게 DLL를 이용하여 로드할수 있는 방법을 의미합니다. 이방법으로 DLL를 로드할경우 3개의 함수를 이용합니다. 
 제일 먼저 라이브러리를 로드하는 LoadLibrary함수입니다. 이함수의 형은 다음과 같습니다.

HINSTANCE LoadLibrary( LPCTSTR lpLibFileName );
 예를 들어서 ExRegularDll.dll이라는 함수를 로드하고자 한다면  다음과 같이 할수 있습니다. 

HINSTANCE hDll;

hDll=LoadLibrary("ExRegularDll.dll");

 LodadLibrary함수를 이용하로 로드하면 인스턴스 핸들을 리턴합니다. 이 인스턴스 핸들을 이용하여 필요한 함수의 포인터를 찾습니다. 예를 들어 ExRegularDll.dll이라는 함수에 현재 윈도우의 화면 크기를 가지고 있는 함수가 Factory라고 한다면 다음과 같이 할수 있습니다. 

typedef int (*FactoryFunc)(int num);

FactoryFunc lpFactoryFunc;

lpFactoryFunc=(FactoryFunc)GetProcAddress(hDll,"Factory");

GetProcAddress함수는 다음과 같은 형태입니다. 

FARPROC GetProcAddress(

HMODULE hModule, // DLL인스턴스

LPCSTR lpProcName //함수 이름

);

 GetProcAddress함수의 첫번째 인자는 로드한 DLL의 인스턴스 핸들이며 두번째 인자는 이 DLL안에 있는 함수이름입니다. GetProcAddress(hDll,"Factory"); 라고 하였을경우 “ExRegularDll.dll"함수안에서 Factory 함수를 찾아서 이 메모리 위치를 리턴하며 위의 예에서는 이 위치를 lpFactoryFunc 가 받는 것입니다. 이렇게 리턴된 lpFactoryFunc 함수를 실행하고자 한다면 다음과 같이 하면 됩니다. 
lpFactoryFunc(num)
 lpFactoryFunc();라고 실행하였을경우 DLL의 Factory 의 함수를 실행한것과 같습니다.  만일 Factory 함수의 안에 인자로 (int num)이 있기 때문에 위와 같이 int num의 인자를 설정한것입니다. 

 이와 같이 라이브러리에서 함수를 실행한후 DLL의 사용이 종료 되면 FreeLibrary함수를 이용하여 해제 하면됩니다.
FreeLibrary(hDll);
 이렇게 하였을경우 현재 DLL를 사용하는 프로그램이 전형 없다고 할경우 그 DLL은 메모리에서 해제되나 만일 다른 프로그래에서 사용하고 있다면 이 DLL 은 메모리에 그대로 있습니다. 메모리에서 DLL를 해제하지 않고 싶을경우 한개의 프로그램이 로드하면서 그DLL를 로드하고 아무것도 이용하지 않은채 해제를 하지 않으면 됩니다. 이렇게 되면 다른 프로그램에서는 언제나 메모리에 상주되어 있는 DLL 를 항상 이용할수 있습니다. 

그리하여 직접 사용해보기~
DLL 파일부로 부터 선언부 발췌

#pragma data_seg("Shared")
HINSTANCE g_Module = NULL;
HHOOK g_hook = NULL;
HWND g_hWnd = NULL;
#pragma data_seg() 

#pragma comment(linker, "/SECTION:Shared,RWS")

__declspec(dllexport) BOOL SetHook( HWND hWnd );
__declspec(dllexport) BOOL RemoveHook();
DLL을 링크한 CPP 파일로 부터 발췌

#pragma comment( lib, "test.lib" )

함수사용부
HINSTANCE hIns = LoadLibrary(_T("CatchDll.dll"));
if( hIns == NULL )
 MessageBox("Load Library fail\n");
typedef void (*defSetHook)(HWND hWnd);
defSetHook fSetHook; 
fSetHook = (defSetHook)GetProcAddress( hIns, "SetHook" );
fSetHook( this->GetSafeHwnd() );
FreeLibrary(hIns);
해당 부분은 직접 구현할 떄 사용한 방법/코드를 그대로 가져온 것이다.
이상하게 implict으로 하면 안된다 ..안습(이거때문에 하루를 날렸음)
  아. 예제 넣는것도 힘들다-_-; (tistory미워요)

pragma에 대한 자세한 사용은 아래의 글, "pragma의 용법"을 보자.

 비쥬얼 스튜디오에서 설정을 통하여 dll 파일을 linking 하는 부분이다.(순차설명)
Project(프로젝트:우클릭 혹은 드랍메뉴)>Property(속성)>Linker(링커)>input(입력)
제일 윗단의 추가종속성에 dll 파일의 경로와 이름을 넣어주면 된다. 상대경로든 절대경로든.
   한글버전의 비쥬얼 스튜디오가 깔려있어서 영문 이름은 정확하지 않다.


  • DLL, 변수를 공유하자
처음 시작은 dll을 링크한 외부에서 dll의 돌아가고 있는 상황을 알고자 함이었다.
  외부에서 DLL 파일의 변수에 접근하고 싶을 때 어떻게 해야할까?

dll에서 생성한 데이터(메모리)를 dll을 사용하는 프로세스(프로그램)에서 사용하는 방법에는 크게 두가지가 있다.
  1. #pragma data_seg의 사용
  2. 메모리맵 파일의 사용
 나는 이번 후킹예제에서 거의 대부분의 사람이 사용할 것이라고 생각하는(검색하였을 떄 양이 더 많다-_-;;) pragma data_seg를 사용하였다.
 따라서 메모리맵 파일의 사용법은 다른데서 찾아보세요- _-)y~

 용이한 자료가 매우 많은 pragma data_seg를 사용한 변수 공유는 사용법도 간편하다.
#pragma data_seg("SHAREDATA")
 int x;
 char y;
#pragma data_seg()
#pragma comment( linker, "SECTION:.SHAREDATA,RWS" )
   위의 pragma들의 자세한 사용에 대해 알고 싶으면 아래의 글을 참조.
 위와 같이 사용하면 된다. dll 파일을 링크하면 x, y의 데이터를 공유할 수 있게 된다.
 
쉽다.


 으흐흐 계속 쉬웠으면 좋겠다 ㅠㅠ
 이걸 위해 몇시간 삽질을 했는지 모름. 대체적인 예제들이 자세한 설명은 앞뒤로 떼먹고 코드만 보여주고 됐지? 타입이라 하나하나 정보를 수집해야만 했다. 특히 pragma 들에 대해-_-
 pragma의 자세한 내용은 아까 말했다시피 아래의 글을 참조.



  • 이제 변수의 공유가 되었으니 함수를 공유하자

이게뭐야-_-; tistory 편집기는 word를 따라가기엔 멀었다. 메뉴만 같이 하다니 밉다.
(글머리 기능&bold,color 사용을 위해 올렸다 내렸다 지웠다 달았다 난리 났다)

함수공유... ㅈㄱ..제일 삽질한 부분이다.

 dll 내부의 공유함수는 다음과 같이 "이~ 함수는~ 외부에서 사용할 것이다~" 라고 컴파일러에게 가르켜 주지 않으면 안된다. 자동인식...절때 그런거 없다 흑.

__declspec(dllexport) BOOL SetHook( HWND hWnd );
__declspec(dllexport) BOOL RemoveHook();

빨간 부분이 DLL 파일에서의 주 요점이다.

함수공유를 위해 프로그램에서 해주어야하는일이 있다.
링크와 선언.

implict방법
pragma 라던가 비쥬얼스튜디오를 사용해 링크해주던간에 일단 dll을 링크해주었다.
그럼 이제 dll내의 함수 사용을 위해 헤더나 파일의 상단에 dll 파일 내의 함수이름을 선언해주어야 한다. 그냥 다른 함수 선언하는 것과 마찬가지로

반환인자 함수이름( 매개변수 );
int testFunc( int name );

해주면 된다.
사용을 위해 이런게 있어 함 찾아봐 이러고, 선언해주는 것이다.
그럼 이제 컴파일시 해당 선언을 보고 linking된 dll 파일로부터 함수를 찾아 수행하게 된다.

explicit방법
좀 길지만 확실한 방법이다.
직접 dll이 컴파일되어있는 lib로 부터 불러들인다.

HINSTANCE hIns = LoadLibrary(_T("CatchDll.dll"));
if( hIns == NULL )
 MessageBox("Load Library fail\n");
typedef void (*defSetHook)(HWND hWnd);
defSetHook fSetHook; 
fSetHook = (defSetHook)GetProcAddress( hIns, "SetHook" );
fSetHook( this->GetSafeHwnd() );
FreeLibrary(hIns);

만세~
여기까지이다.
DLL 파일의 생성부터 자세한 설명까지

http://ccmc.knu.ac.kr/files/research/sdl_home/dll/subject1.htm
http://blog.naver.com/kyehwan2?Redirect=Log&logNo=10005701934
http://msdn.microsoft.com/library/default.asp


출처 : http://mayu.tistory.com/9

'system > windows' 카테고리의 다른 글

PE patch를 이용한 DLL loading  (0) 2012.06.15
가상 키 코드(스캔코드) 테이블  (0) 2012.03.06
관리자 권한 실행 - UAC 고려하기  (0) 2012.01.16
Segmentation 시발점 찾다가  (0) 2011.10.31
110901 긁적긁적  (0) 2011.09.01
:

관리자 권한 실행 - UAC 고려하기

system/windows 2012. 1. 16. 16:31
- 요약
1. ShellExecute runas
2. 링커 리콰이어
3. 매니페스트


- ShellExecute 를 사용 하는 방법

if(IsUserAnAdmin() == FALSE) //프로그램이 관리자 권한인지 알 수 있는 함수
{
//관리자 권한으로 실행 시킨다.
SHELLEXEGUTEINFO si
ZeroMemory(&si, sizeof(SHELLEXECUTEINFO));

si.cbSize = sizeof(SHELLEXECUTEINFO);
si.hwnd = NULL;
si.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
si.lpVerb = _T("runas");
si.lpFile = _T("프로그램명");
si.lpParameters = _T("파라미터");
si.nShow = SW_SHOWNORMAL;
si.lpDirectory  = NULL;
ShellExecuteEx(&si);
}

- Visual C++ 2008 일 경우 설정

 Project > Properties 메뉴를  선택
 Linker > Manifest File 항목에서
 Enable User Account Control (UAC)를 Yes로 설정하고
 UAC Execution Level을 requireAdministrator로 설정한다.

- 매니페스트 파일 생성

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="1.00.0"
     processorArchitecture="X86"
     name="IsUserAdmin"                       
     type="win32"/>
  <description>Description of your application</description>
  <!—어플리케이션 보안 요구 사항을 식별합니다. -->
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="requireAdministrator"
          uiAccess="false"/>
        </requestedPrivileges>
       </security>
  </trustInfo>
</assembly>

위의 내용으로 manifest 라는 XML 파일을 생성한다.

name="IsUserAdmin" 여기에 실행파일 명을 명시!!!
level="requireAdministrator" 인 경우 관리자 권한으로 프로그램 실행됨.
level="asInvoker" 인 경우 부모 프로세스와 동일한 토큰으로 실행됨(경험적 결과이나 일반사용자 권한으로 실행됨)


위의 파일을 응용프로그램 안으로 통합하는 방법은 여기 http://blogs.msdn.com/shawnfa/archive/2006/04/06/568563.aspx  를 참고하십시오.


- 출처
http://happybird.tistory.com/13  
 

'system > windows' 카테고리의 다른 글

가상 키 코드(스캔코드) 테이블  (0) 2012.03.06
쉽게 쓴 dll  (0) 2012.02.24
Segmentation 시발점 찾다가  (0) 2011.10.31
110901 긁적긁적  (0) 2011.09.01
dll injection 기초  (0) 2010.09.03
:

Segmentation 시발점 찾다가

system/windows 2011. 10. 31. 14:34
Segmentation 시발점 찾다가 생각나서 그림으로 정리

결론은, 80286


 


'system > windows' 카테고리의 다른 글

쉽게 쓴 dll  (0) 2012.02.24
관리자 권한 실행 - UAC 고려하기  (0) 2012.01.16
110901 긁적긁적  (0) 2011.09.01
dll injection 기초  (0) 2010.09.03
win 명령어  (0) 2010.08.05
:

110901 긁적긁적

system/windows 2011. 9. 1. 17:51
세그먼트 레지스터
- 세그먼트 디스크립터 테이블 인덱스를 보유

그 인덱스를 찾아 세그먼트 디스크립터 테이블을 참조하게 되고
그 세그먼트 디스크립터 테이블에는 세그먼트 메모리가 있음


각 세그먼트 레지스터가 가리키는 세그먼트 디스크립터와 + 가상메모리(os에서 사용자가 지정한 메모리 주소)
- 선형주소가 됨
- 이렇게 사용자가 지정한 메모리 주소로부터 선형 메모리까지 얻어지는 과정을 "세그먼테이션" 이라 칭함


선형주소 + 페이징 기법으로 
- 물리주소가 됨
- 접근하고자 하는 메모리에 대한 세그먼테이션 과정이 끝나면 프로세서는 과정에서 도출된 얻어진 선형 메모리로 부터 
페이징 메커니즘에 의해 물리 메모리 주소를 가지고 오게 됨


가상메모리 - 선형메모리 - 물리메모리

가상메모리는 gdt, ldt 로 선형주소와 매칭
- gdt(global) : 모든 프로그램이 참조할 수 있는 세그먼트 디스크립터들의 모임
- ldt(local) : 멀티테스킹 환경에서 각 테스크 단위로 정의


거기서 나온 선형주소는 페이지 디렉토리와 페이지 테이블을 참조하여 물리주소와 매칭



세그먼트 셀렉터
- index :
세그먼트 디스크립터 테이블에 있는 디스크립터의 배열에서 어떤 것을 선택할 것인지 나타냄
- ti(table indicator) : 
get=0, ldt=1
- rpl(request privilege level) : 요청한 놈에 대한 권한레벨
특권레벨, 예를 들어 커널모드
보호모드는 권한에 따른 제어가 가능한데 바로 rpl, dpl 때문, 이를 비교하여 접근을 제어


하위 3bit가 다른 용도로 사용되므로, index는 01000(8), 10000(16)... 등으로 8씩 증가되는 것처럼 보일것임
디스크립터주소 = gdt주소 + (index*8) 여기서, index에 8을 곱하는 이유는 디스크립터가 8byte이기 때문)


윈도우의 하위 2Gbyte (0 ~ 0x7fffffff) :  유저레벨에서 사용 (어플리케이션이 사용)
윈도우의 상위 2Gbyte (0x80000000 ~ 0xffffffff) : 커널레벨에서 사용



cdecl(C lib)
-아래와 같이 콜러가 스택 정리
00401000    PUSH EBP                        ; add() 시작
00401001    MOV EBP,ESP
00401003    MOV EAX,DWORD PTR SS:[EBP+8]
00401006    ADD EAX,DWORD PTR SS:[EBP+C]
00401009    POP EBP
0040100A    RETN

...

00401010    PUSH EBP                        ; main() 시작
00401011    MOV EBP,ESP
00401013    PUSH 2
00401015    PUSH 1
00401017    CALL callconv.00401000          ; => add() 호출
0040101C    ADD ESP,8                       ; => stack 정리
0040101F    POP EBP                       
00401020    RETN



stdcall(Win32 API)
-아래와 같이 콜리가 스택 정리. 참 착하네
00401000    PUSH EBP                        ; add() 시작
00401001    MOV EBP,ESP
00401003    MOV EAX,DWORD PTR SS:[EBP+8]
00401006    ADD EAX,DWORD PTR SS:[EBP+C]
00401009    POP EBP
0040100A    RETN 8 -- 리턴 + 팝

...

00401010    PUSH EBP                        ; main() 시작
00401011    MOV EBP,ESP
00401013    PUSH 2
00401015    PUSH 1
00401017    CALL callconv.00401000
0040101C    POP EBP
0040101D    RETN


이 함수를 스탠다드콜로 하고 싶다 할땐 아래와 같이 하면 됨
int _stdcall example(int a, int b)


fastcall
기본적으로 stdcall과 같으나, 함수에 전달하는 파라미터 일부(2개 까지)를
스택 메모리가 아닌 레지스터를 이용하여 전달.

예를 들어 파라미터가 4개 일때, 앞의 2개 파라미터는 ecx, edx 를 이용하여 전달

당연히 레지스터를 쓰니 메모리 보다 함수 호출이 빠를 수 밖에..
사실 속도성보다는 편의를 위해 사용.

그러나 ecx, edx 백업 필요 존재 - 다른 값이 쓰여지니까

=====================================
expertprogrammer.tistory.com
rootkit.tistory
reversecore.com
nobless_06.blog.me
 

'system > windows' 카테고리의 다른 글

관리자 권한 실행 - UAC 고려하기  (0) 2012.01.16
Segmentation 시발점 찾다가  (0) 2011.10.31
dll injection 기초  (0) 2010.09.03
win 명령어  (0) 2010.08.05
컬링 컨벤션 세가지(cdecl,stdcall,fastcall)  (0) 2010.07.07
:

dll injection 기초

system/windows 2010. 9. 3. 12:45

'system > windows' 카테고리의 다른 글

Segmentation 시발점 찾다가  (0) 2011.10.31
110901 긁적긁적  (0) 2011.09.01
win 명령어  (0) 2010.08.05
컬링 컨벤션 세가지(cdecl,stdcall,fastcall)  (0) 2010.07.07
메모리 관리와 함수  (0) 2010.07.06
:

win 명령어

system/windows 2010. 8. 5. 22:20

calc .................................... 계산기

charmap ..............................  문자표

cleanmgr .............................  디스크정리

clipbrd ................................  클립보드에 복사된 내용표시

cmd ....................................  도스명령프롬프트 실행 

control ................................  제어판

dfra.msc .............................  디스크조각모음

dxdiag ................................  다이렉트X 진단도구 및 그래픽과 사운드의 세부정보

eudcedit .............................  사용자정의 문자 편집기

explorer ..............................  탐색기

maqnify ...............................  돋보기

mobsync .............................  동기화

msconfig .............................  시작프로그램 제어등 많은 기능 제공

msinfo32 .............................  시스템정보

mstsc .................................  원격 데스크톱 연결

netstat ................................  현재열린포트와 TCP/IP 프로토콜정보를 보여줌

notepad ..............................  메모장

ntbackup ............................  백업 및 복원 마법사

osk ....................................  화상키보드

pbrush ...............................  mspaint그림판

ping ................................... 사이트주소핑테스트 해당 사이트의 인터넷연결 유무 확인

regedit ...............................  레지스트리 편집기

sfc ....................................  시스템 파일 검사기

sndrec32 ............................  녹음기

sndvol32 ............................. 시스템 사운드 등록정보, 볼륨조절

sysedit ...............................  autoexec.bat, config.sys, win.ini, system.ini 시스템구성편집기

systrav ............................... 사운드 볼륨설정 노란색 스피커 아이콘을 트라이목록에 띄움

telnet .................................. open사이트주소(텔넷접속명령어)

telnet open .........................  사이트주소텔넷접속 명령어

tourstart .............................  윈도우 기능안내 html 문서표지

wab ................................... 주소록

winmine ............................. 지뢰찾기

winver ............................... 윈도우 버전확인

wmplayer ........................... 윈도우 미디어 플레이어

wordpad ...........................  워드패드

wscui.cpl ..........................  보안센터

wupdmar ............................ 윈도우업데이트

 


'system > windows' 카테고리의 다른 글

Segmentation 시발점 찾다가  (0) 2011.10.31
110901 긁적긁적  (0) 2011.09.01
dll injection 기초  (0) 2010.09.03
컬링 컨벤션 세가지(cdecl,stdcall,fastcall)  (0) 2010.07.07
메모리 관리와 함수  (0) 2010.07.06
:

컬링 컨벤션 세가지(cdecl,stdcall,fastcall)

system/windows 2010. 7. 7. 00:00
출처 : http://chaosura.egloos.com/4197783

# 함수 호출시에 사용한 매개변수를 정리하는 세가지 방법

- 함수가 종료 된 후에 호출시 사용한 매개변수를 저장한 스택 위치를 정리해 주는 방법으로 esp의 위치를 함수 호출이 일어나기 전의 위치를 옮겨 주는 것

1. __cdecl
  - c/c++에서 디폴트로 사용
  - 함수 호출 시 매개변수가 제일 우측에서 좌측 순서로 스택에 쌓인다
  - 함수를 호출한 부모함수측에서 스택을 정리해 준다.([add esp, 숫자]의 형태로 표현)

2. __stdcall
  - Windows API 에서 사용
  - 함수 호출 시 매개변수가 제일 우측에서 좌측 순서로 스택에 쌓인다
  - 호출당한 자함수측에서 스택을 정리 해준다. ([ret 숫자]의 형태로 표현)

3. __fastcall
  - 매개변수가 두개 이하라면 ecx레지스터와 edx레지스터를 사용하며, 세개 이상이라면 가장 우측부터 스택에 쌓인다.
  - 호출당한 자함수측에서 스택을 정리 해준다.
  => ecx레지스터와 edx레지스터를 매개변수 호출에 사용하기 때문에 스택에 ecx와 edx를 넣어 두고, 매개변수가 정리 된 후 스택에서 pop 시켜서 ecx와 edx를 복구 시켜준다.

'system > windows' 카테고리의 다른 글

Segmentation 시발점 찾다가  (0) 2011.10.31
110901 긁적긁적  (0) 2011.09.01
dll injection 기초  (0) 2010.09.03
win 명령어  (0) 2010.08.05
메모리 관리와 함수  (0) 2010.07.06
:

메모리 관리와 함수

system/windows 2010. 7. 6. 11:25
32. 메모리 관리와 함수


32.1. 메모리 모델에 대하여


볼랜드사의 컴파일러는 메모리 모델이라는 것을 제공합니다. 메모리 모델이란 메모리 안에서 프로그램을 어떻게 실행시킬 것인지를 결정하는 메모리관리의 모델이라고 보시면 됩니다. 메모리 모델에 관해서는 어셈블리어 공부를 하지 않은 이상 쉽게 이해하기 힘든 부분이므로 메모리모델이라는 것이 있다 하는 정도만 알고 넘어가시면 됩니다. 메모리모델을 다루는 문제는 기초과정에서 다룰 문제가 아니므로 다음 기회에 다루도록 하겠습니다.

또한 도스에서는 메모리 모델을 사용하지만, 윈도용 프로그램은 도스와는 다른 메모리 모델을 가지고 있습니다. 때문에 윈도에서는 메모리 모델이라는 이름을 사용하지 않고 옵션을 통해서 조정합니다.

일단 터보C에서 제공하는 메모리 모델 6가지를 간단하게 정리해두었으니 참고하시기 바랍니다. 실제로 메모리 모델을 사용하는 경우는 거의 없지만 참고사항으로 정리해두었습니다. 메모리 모델은 컴파일러 옵션에서 결정할 수 있다는 것만 기억하시기 바랍니다. 메모리 모델은 초보자에게는 너무 골치 아픈 이야기이므로 이번 장은 읽지 않고 지나가셔도 좋습니다.

32.1.1. 초소형 모델(tiny model)

초소형 모델은 확장자가 com인 파일을 만들 때 사용합니다.

가장 작은 메모리 모델입니다. 이 모델에서는 모든 세그먼트 레지스터가 동일한 번지에 존재합니다. 그래서 항상 CS와 DS, SS, ES가 같은 번지를 가진다고 보시면 됩니다. CS DS니 하는 말들이 무엇을 뜻하는지 이해하실 필요는 없습니다. 그냥 그런 것이 있나보다 하고 넘어가시면 됩니다.

이 모델의 특징만 말씀드리면 64KByte의 메모리 공간만이 할당된다는 점입니다. 그래서 640KByte의 나머지 메모리 공간은 제어할 수 없습니다. 또 모든 포인터는 근거리 포인터로 내정됩니다. 역시 무슨 소리인지 잘 모르시겠죠?

딱 하나만 알고 계시면 됩니다. 이 모델만이 확장자가 com인 *.COM 파일을 만들 수 있다는 것입니다. 그러니까 다른 메모리 모델로 설정해놓고 프로그램을 만들면 모두 EXE 파일로만 만들어진다는 것입니다. com파일을 만들려면 exe2bin.exe이라는 프로그램을 사용하거나 링크할 때 /t 옵션을 지정하는 방법을 이용합니다. com파일을 만들 수 있기 때문에 램상주 프로그램을 만들 때 주로 사용하는 메모리모델입니다.

세그먼트란 메모리를 일정 크기로 나눈 블럭으로 64KB를 단위로 삼습니다.

이쯤에서 세그먼트에 대해서는 약간의 설명이 필요할 것 같군요. 세그먼트란 메모리 관리의 효율성을 위해서 메모리를 일정 크기로 나눈 블럭을 말합니다. 그러니까 하나의 논리적 단위가 되는 것입니다.

8086 CPU는 20비트, 즉 최대 1MByte의 번지 공간(address space)을 가집니다. 그러나 1메가를 한 번에 제어하지는 못하고 한 번에 64KByte까지만 제어할 수 있도록 되어 있습니다. 그 이유는 메모리 관리상의 효율과 처리 속도의 증대를 위해서입니다.

그러나 원래는 8비트급 CPU인 8080과의 상위 호환성을 유지하기 위해서 64KByte의 세그먼트 개념이 도입된 것으로 볼 수 있습니다. 즉 IBM PC 이전에 사용하던 8비트 컴퓨터인 애플 컴퓨터 등에서 64KByte의 메모리를 이용했기 때문에 프로그램의 크기가 64KByte를 넘지 못했던 것입니다. 애플 시절에는 프로그램의 크기를 64Kbyte 이내에서 만들었습니다. 이 때문에 실행파일의 크기가 64KByte 이내로 정해졌고, 프로그램이 실행되면서 관리할 메모리의 크기 역시 64KByte면 충분했던 것입니다. 이런 이유로 메모리의 세그먼트 단위가 64KByte가 된 것입니다.

8086 CPU는 8080와 8085를 바탕으로 미국의 인텔사가 개발한 CPU입니다. 이 CPU는 데이터버스를 16비트 폭으로 확장하여 2바이트 단위의 워드 단위 연산을 하므로 속도가 빠릅니다. 그리고 1메가(00000H ~ FFFFFH)의 넓은 메모리 공간을 가질 수 있습니다. 또한 번지 지정방식이 강화돤 CPU입니다. 그러나 1메가바이트의 메모리를 한꺼번에 전부 사용할 수 는 없습니다. 그래서 1MByte의 공간을 64KByte의 번지 공간으로 나누어 효과적으로 제어하기 위해 "세그먼트(segment)"라는 새로운 개념이 도입됩니다. 즉 세그먼트는 1MByte의 메모리를 64KByte씩 잘라 놓은 덩어리로 보셔도 됩니다.

8086 CPU는 CPU 안의 주소를 구분해놓은 레지스터를 가집니다.

8086 CPU는 몇 가지 레지스터를 가집니다. 레지스터는 CPU를 일종의 번지에 의해서 구분해놓은 단위라고 보시면 됩니다. 쉽게 말하면 CPU 안의 주소입니다. 레지스터는 플래그 레지스터, 주레지스터, 포인터 인덱스 레지스터, 세그먼트 레지스터로 나눕니다.

주레지스터는 A, B, C, D라는 이름에 X를 붙여 축적연산을 하는 AX(어큐뮬레이터 레지스터), 번지 포인트용인 BX(베이스 레지스터), 카운터용인 CX(카운트 레지스터), 데이터용으로 쓰는 DX(데이터 레지스터)로 나눕니다. 이들은 다시 상위 8비트 길이를 사용할 때는 H를 붙이고, 하위 8비트를 사용할 때는 L을 붙여서 AH, AL, BH, BL, CH, CL, DH, DL로 구분합니다. 이 레지스터를 자유롭게 제어하려면 어셈블리어를 배워야 하므로, 이 글을 읽을 때는 AX나 AH가 무엇을 가리키는 말인지 알고 계시면 충분합니다.

그리고 포인터 인덱스 레지스터에는 SP(스택 포인터), BP(베이스 포인터), SI(소스 인덱스), DI(데스티네이션 인덱스), 인스트럭션 포인터(IP)로 구분합니다. 인스트럭션 포인터는 명령을 메모리에서 읽어내기 위해서 사용하며, 스택 포인터는 스택의 최고 윗 번지를 구하기 위해 사용합니다. SI, DI, BP는 메모리 내의 데이터를 가리키기 위해서 사용합니다.

그리고 우리가 자주 접하게 될 세그먼트 레지스터로는 CS, DS, ES, SS 등이 있습니다. 즉 4개의 특정 64 세그먼트를 각각 코드, 데이터, 스택, 여분(엑스트라) 세그먼트라고 부릅니다. 즉 64x4=256KByte이므로 최대 256KByte의 공간을 직접 참조할 수가 있고 그 외의 공간은 직접 참조할 수가 없습니다.

코드 세그먼트는 기계어 명령(machine instruction)이 놓여 있는 곳이고 데이터 세그먼트는 각종 데이터(변수 등)이 놓이는 곳이고, 스택 세그먼트는 물론 스택입니다. 그 밖에 여분 세그먼트는 추가적인 데이터가 놓이는 곳입니다.

이들 세그먼트는 각각 CS, DS, SS, ES라는 16비트의 세그먼트 레지스터에 의해 그 시작 번지가 결정됩니다. 즉 세그먼트 레지스터 CS, DS, SS, ES는 이들 세그먼트 레지스터의 선두번지를 지시하는 낱말입니다.

메모리를 참조할 때는 세그먼트 값과 오프셋 값을 사용합니다.

그런데 이들 메모리를 참조할 때는 물리번지를 사용하지 않고 세그먼트 값과 오프셋 값을 이용해서 참조합니다. 그 까닭은 세그먼트 레지스터는 16비트의 길이를 가지기 때문에 20비트 길이인 번지값을 다 기록할 수 없기 때문입니다. 그래서 하위 4 비트를 삭제하여 저장합니다. 즉 10000H라는 번지는 16이라는 숫자의 단위인 2번째 자리를 생략하고 1000H라고 저장하는 것입니다. 따라서 세그먼트번지는 2의 4제곱인 16칸 만큼의 간격을 두고 가리키게 됩니다. 즉 각 세그먼트 사이는 16번지의 차이가 생기는 셈입니다.

오프셋값은 세그먼트 번지로부터의 간격을 말합니다. 즉 오프셋값이 3000H라고 하면 시작번지로부터 3000번지 뒤의 번지를 가리키는 셈입니다. 이럴 경우 시작번지가 1000H고 오프셋값이 3000H일 경우 1000+3000=4000H가 번지값이 되는 것이 아닙니다. 시작번지 1000H는 4비트를 잘라낸 것이므로 16번지에 해당하는 자리수를 하나 더 채워주어야 합니다. 즉 1000H는 10000H로 바꾼 다음에 계산해야 합니다. 따라서 시작번지가 1000H이고, 오프셋값이 3000H라면 10000H+3000H=13000H가 됩니다. 즉 13000번지가 실질적인 물리번지가 되는 것입니다.

번지를 참조하는 방법이나 절대번지를 구하는 방법은 고급과정에서 자세하게 배울 것이므로 초급과정인 이 책에서는 그저 세그먼트나 오프셋이 이런 개념을 가지고 있구나 하는 정도만 말씀드리고 끝내겠습니다.

**요약: 메모리를 어떻게 관리하느냐에 따라서 메모리모델을 나누어 프로그램을 만드는데 초소형모델은 64KByte 이하의 작은 실행파일을 만들 때 사용하는 메모리 모델입니다. 확장자가 com인 파일은 초소형 모델에서만 만들 수 있습니다. 그리고 세그먼트란 64KByte씩 나눈 메모리 공간의 한 단위(블럭)을 말하며, 오프셋값은 세그먼트 번지로부터의 상대적인 거리를 가리키는 번지값입니다.

32.1.2. 소형 모델(small model)

터보C에서는 별도의 기본적으로 소형 모델로 프로그램을 컴파일합니다.

이 모델에서는 DS와 SS, ES는 같지만 DS만 다릅니다. 달리 말해서 세그먼트들이 분리된다는 이야기입니다. 달리 말한다는 것이 더 어려운 이야기가 되었군요. 더 어렵게 말씀드리면 코드영역과 스택영역이 분리되기 때문에 자료들이 서로 침범하지 않게 된다는 말인데 꼭 기억해두실 내용은 하나 뿐입니다.

터보C에서는 별도의 컴파일러 옵션을 지정하지 않는 경우 소형 모델을 기본 메모리 모델로 설정한다는 점입니다. 즉 터보C를 설치한 후에 아무런 옵션의 변경 없이 프로그램을 제작했다면 소형모델로 프로그램이 만들어진다는 점입니다. 이 말은 크기가 크지 않은 프로그램은 대부분 소형 모델로 만든다는 뜻입니다.

**요약: 소형모델은 터보C에서 기본적으로 설정한 메모리 모델로 크기가 크지 않은 프로그램을 만들 때 사용합니다.

32.1.3. 중형 모델(medium model)

중형 모델로 만든 프로그램은 64Kbyte 이상의 크기를 가진 자료는 불러올 수 없습니다.

이 모델에서는 함수 포인터가 원거리 포인터로 내정되고 데이터포인터는 근거리 포인터로 내정됩니다. 그래서 함수는 64KByte의 크기를 넘어갈 수 있지만 자료는 64KByte의 공간을 넘어갈 수 없습니다. 자료가 64KByte를 넘어갈 수 없다는 것이 무슨 말일까요? 가장 쉽게 말하자면 배열이나 변수에 저장할 수 있는 자료의 양이 64KByte 이상은 저장할 수 없다는 이야기입니다.

예를 들어서 문서파일에서 문서파일을 불러와서 변수에 저장해서 편집한다고 합시다. 이럴 경우에 변수에서 다룰 수 있는 자료의 크기가 64KByte밖에 안되므로 64KByte가 넘는 큰 문서파일일 경우에는 읽어오지 못한다는 문제가 생기는 겁니다. 즉 뒷부분을 자르고 불러와야 합니다.

게임 등을 만들 때는 화면을 저장하는 기술을 많이 사용하는데 이럴 경우에는 한 변수나 배열에 64KByte 이상의 자료를 담아야 합니다. 그래서 그때는 중형모델이 아니라 대형모델을 많이 사용합니다.

**요약: 중형 모델은 함수 포인터는 원거리 포인터를 사용하고 데이터포인터를 근거리 포인터를 사용하므로 자료는 64Kbyte 이상의 크기로 저장될 수 없습니다.

32.1.4. 중소형 모델(compact model)

이 모델은 중형 모델과는 반대로 데이터 포인터는 원거리 포인터로 내정되고 함수 포인터는 근거리 포인터로 내정됩니다. 그리고 각각의 세그먼트 들은 독립적으로 존재하며 서로 영역을 침범하지 않습니다. 데이터를 64KByte 이상 다룰 수 있기 때문에 덩치가 큰 자료를 다루는 프로그램에 많이 이용하는 모델입니다.

32.1.5. 대형 모델(large model)

대형 모델은 64KByte 이상인 exe파일을 만들 때 사용합니다.

이 모델은 함수 포인터와 데이터 포인터가 모두 원거리 포인터로 내정되어 컴파일됩니다. 복잡한 이야기 생략하고 결론만 말씀드리면 이 프로그램은 덩치가 큰 프로그램에 사용합니다. 쉽게 말해서 프로그램의 크기가 64KByte 이상인 *.exe 파일들은 대부분 이 모델로 컴파일되었다고 보시면 됩니다.

그러니까 우리가 일반적으로 사용하는 대부분의 프로그램은 대형모델에서 컴파일합니다. 그리고 앞으로 우리가 게임을 만들거나 조금 복잡한 프로그램을 만들 때도 대형모델에서 대부분 제작합니다. 그러므로 이 시간 이후부터는 메모리모델을 대형모델로 설정해놓고 프로그램을 만드는 것이 좋습니다.

**요약: 대형 모델은 함수 포인터와 데이터 포인터가 모두 원거리 포인터를 사용합니다. 크기가 64KByte 이상인 exe 파일은 대부분 대형모델에서 만듭니다.

32.1.6. 거대 모델(huge model)

대형모델과 거의 다 같으나 정적데이터 영역을 64KByte 이상 가질 수 있다는 점이 다릅니다. 덩치가 큰 특수한 자료 파일을 실행파일 안에 저장하고 싶을 때 사용하며 평상시에는 거의 사용하지 않습니다. 특수한 자료파일이란 글꼴파일이나 그림파일 등을 말합니다.

32.2. 주소 또는 번지


주소란 각종 자료가 위치할 컴퓨터 내의 위치를 말합니다.

프로그램을 짜는 사람이 가장 골머리를 앓는 부분이 주소와 관련된 내용입니다. 앞서 변수를 미리 선언해두면 자리를 마련해둔다고 했습니다. 이때 마련하는 자리는 나름대로의 위치가 정해져 있을 겁니다. 주소의 개념을 넓게 생각하면 무슨 동 몇 번지라고 표현할 수 있고, 좁게 생각하면 한 건물 안에서 몇 층 몇 호라고 표현할 수 있습니다. 대부분의 작업공간은 주소를 가지고 있습니다. 집도 공장도 사무실도 모두 주소를 가지고 있습니다. 그런데 하나의 주소에 아무런 관계가 없는 두 사람을 집어넣으면 어떻게 되겠습니까? 큰 문제가 발생할 겁니다. 비행기표를 끊고 탔는데, 같은 좌석번호에 두 명이 배정되었다거나 호텔 방에 들어갔더니 다른 사람들이 자기가 예약한 방이라고 우기면 난리가 납니다. 집을 하나 샀는데 이중 등기가 되었다 해도 문제입니다. 통상 하나의 주소에는 한 명의 소유자를 인정하기 마련입니다.

마찬가지로 컴퓨터 안에도 각종 주소가 있고 각 주소를 점유할 수 있는 소유자도 한 명이어야 합니다. 컴퓨터의 주기판에 장착된 부품이 나름대로 고유한 주소를 가지고 있습니다. 그러나 프로그램을 짤 때 가장 중요한 주소는 역시 램의 주소입니다. 램을 하나의 작업공간인 사무빌딩이나 공장으로 생각해봅시다.

주인인 내가 하드디스크에 든 파일목록을 정리해서 프린터로 출력하라고 명령을 내렸습니다. 그런데 컴퓨터가 파일목록을 정리한 자료는 일단 3층 10호 방에 넣어두고, 복사할 때는 2층 4호 방에 있는 자료를 가져다가 프린터로 출력했다고 합시다. 이러면 작업내용이 엉망이 되는 셈입니다. 그러므로 파일목록을 정리한 자료를 3층 10호 방에 보관해두라고 했으면, 나중에 그 자료를 가져올 때도 3층 10호 방에 가서 가져와야 합니다. 엉뚱한 방을 찾아들어가면 골치 아픈 문제가 생깁니다.

컴퓨터에서 다루는 주소는 인간 세계의 주소와 같은 개념입니다.

컴퓨터를 다루거나 프로그램을 짜는 사람이 가장 골치 아프게 생각하는 것이 바로 주소와 관련한 내용입니다. 몇 층 몇 호실에 무슨 자료를 넣어두었는지 일일이 파악을 하고 있어야 하기 때문입니다. 문제는 이들 주소가 사람들이 알기 쉽도록 표기되지 않고 복잡한 이진수나 16진수로 표시된다는 점입니다. 그러다보니 1333번지에 있는 자료를 가져와서 더하라고 명령을 내려야 하는데 1332번지 자료를 가져와서 더하라고 명령을 내리기 일쑤입니다.

우편물을 정확하게 배달하는 것이 쉬운 일이 아닌 것처럼 원하는 주소에 원하는 자료를 배달하고 다시 가져오는 일도 쉬운 일이 아닙니다. 우편물에 우편번호와 주소를 정확하게 써야 하는 것처럼 컴퓨터에서도 정확한 주소를 적어주고 명령을 내려야 자료의 유실을 막을 수 있습니다. 하여간 컴퓨터에서 말하는 주소는 일반적인 사회에서 말하는 주소와 같은 개념이라는 점을 알아두시기 바랍니다.

**요약: 컴퓨터가 자료를 저장할 때는 일정한 규칙에 의해서 정한 주소(또는 번지)를 사용합니다. 즉 주소란 컴퓨터가 자료를 저장해둔 위치를 가리키는 말입니다. 한 주소에는 하나의 자료만 저장할 수 있습니다.

32.3. 선입선출과 후입선출의 차이


선입선출(FIFO=First In First Out)은 먼저 들어간 놈이 먼저 나온다는 뜻입니다. 즉 먼저 집어넣은 자료가 먼저 나온다는 이야기입니다. 선입선출의 개념을 비교하면 입구와 출구가 있고 한 사람이 통과할 수 있는 긴 복도를 통과하는 일과 같습니다. 즉 입구 쪽에서 사람이 들어가면 먼저 들어간 사람이 출구 쪽으로 나오게 될 겁니다. 그러므로 선입선출은 보통 두 개의 문이 존재합니다. 들어가는 문과 나가는 문이 따로 있는 겁니다. 양쪽에 구멍이 있는 호스가 있을 때 한 쪽에서 구슬을 넣으면 먼저 들어간 구슬이 다른 구멍으로 나오는 먼저 나오는 것과 같습니다.

후입선출(LIFO=Last In First Out)은 이와 반대로 먼저 들어간 자료가 가장 늦게 나오는 것을 말합니다. 이는 출구가 따로 없는 좁은 복도에 사람을 집어넣는 일로 비유할 수 있습니다. 즉 들어간 문이 나가는 문이 될 경우에는 먼저 들어간 사람보다는 맨 마지막에 들어간 사람이 나올 때 먼저 나오게 됩니다. 호스 한 쪽을 막고 구슬을 넣은 다음에 다시 구슬을 빼면 가장 늦게 들어간 구슬이 먼저 나오는 것과 같습니다.

선입선출과 선입후출은 주로 메모리를 다룰 때 자주 접하게 되는 개념입니다. 예를 들어서 우리가 배운 자동변수는 스택이라는 기억장소에 저장되는데 이때 스택은 후입선출방식으로 메모리를 관리하는 곳입니다. 그래서 자료를 집어넣을 때는 밀어넣기로 집어넣고, 나올 때는 밀어넣은 순서와 반대로 튀어나옵니다. 택시를 타면 택시기사들이 사용하는 동전보관통을 생각하면 후입선출의 예를 쉽게 알 수 있습니다.

[보기] 후입선출의 보기

- 비어있을 때
T

- 10을 넣음
10
T

- 20을 넣음
20
10
T

- 30을 넣음
30
20
10
T

- 30부터 뺌
20
10
T

- 다음에 20을 뺌
10
T

반면 선입선출은 힙이라는 메모리에서 주로 사용하는 방식으로 힙에는 배열과 초기화된 전역 변수 등이 저장됩니다.

[그림] 선입선출의 보기

- 비어있을 때
입구| | | |출구

- 10을 넣음
입구|10| | |출구

- 20을 넣음
입구|20|10| |출구

- 30을 넣음
입구|30|20|10|출구

- 40을 넣음
입구|40|30|20|출구=) 10 (출구로 10이 나옴)

그림을 통해서 두 방식의 차이를 알 수 있으리라 생각합니다. 이 책에서는 두 방식이 어떤 차이를 가지고 있는지 정도만 이해하시면 될 것으로 생각합니다.

32.4. 코드, 데이터, 스택, 힙, 큐, 데크의 의미와 차이


언어 책을 보면 스택이나 힙, 큐, 데크라는 말이 나옵니다. 물론 이 말의 뜻을 몰라도 프로그램 짜는데 어려움은 없습니다. 모든 것은 컴파일러라 알아서 해주니까요. 그렇지만 용어의 의미도 모르고 프로그램을 만들려면 조금 답답합니다.

이들 용어는 사용하는 곳에 따라서 의미가 조금 다릅니다. 자료 구조에서 사용할 때와 메모리에서 사용할 때 의미가 조금씩 다릅니다. 자료 구조론에서는 스택과 큐, 데크 등의 용어를 사용합니다. 반면 프로그램을 만들 때는 스택과 힙이라는 용어를 많이 사용합니다.

먼저 우리가 보통 스택과 큐, 힙을 말할 때는 C나 C++의 메모리 구조와 관련된 용어로 사용 합니다. C/C++에서 메모리는 다음과 같은 계층을 이룹니다.

1. 코드(code) 영역
2. 데이터(data) 영역
3. 힙(heap) 영역
4. 스택(stack) 영역

코드 영역은 코드 자체를 구성하는 메모리 영역입니다. 즉 프로그램 명령이 위치하는 곳으로 기계어로 제어되는 메모리 영역입니다. 하위 메모리라고 부르는 가장 낮은 쪽에 있는 메모리 영역입니다. 이 부분은 기계어 부분이므로 프로그래머가 신경 쓸 이유가 없습니다.

데이터 영역에는 데이터가 보관됩니다. 예를 들면 전역(global) 변수, 정적(static) 변수, 그외 초기화된 각종 배열과 구조, 자료들이 저장됩니다.

힙 영역은 프로그래머가 스스로 할당한 메모리 영역을 뜻합니다. 즉 터보C의 함수 중에 메모리를 할당하는 함수인 malloc() 등을 사용하여 배정한 메모리가 힙 영역에 해당합니다. 메모리 모델에 따라서 사용하는 함수가 달라지는데 메모리 할당 때는 malloc() farmalloc() 함수를 사용하고 재배정 때는 realloc() 함수를, 메모리 해제 때는 free()나 farfree() 함수를 사용합니다.

스택 영역은 프로그램이 자동으로 사용하는 임시 메모리 영역에 해당합니다. 즉 자동 변수를 저장하거나 함수로 인수를 보낼 때, 복귀 번지를 저장할 때 등에 사용합니다.

스택과 힙은 사용 용도에 따라서 조금씩 다른 의미로 사용합니다. 예컨대 버퍼 메모리에서 스택고 힙이라는 용어를 사용하면 버퍼 메모리를 구성하는 두 가지 방식을 뜻합니다. 이때 스택은 후입선출(LIFO=Last In First Out) 방식의 버퍼를 말하고, 힙은 선입선출(FIFO=First In First Out) 방식의 버퍼를 뜻합니다.

스택의 경우 후입선출 방식이므로 동작 과정이 푸시(push)와 팝(pop)의 과정으로 이루어집니다. 이를 통해 동작이 한 쪽 끝(top)에서만 일어납니다. 다시 말해서 자료가 들어가는 구멍(입구)과 나오는 구멍(출구)이 하나입니다. 이 때문에 맨 마지막에 들어간 것이 제일 먼저 나오는 겁니다.

큐(Queue)는 프로그램 언어에서 보면 자료 구조의 한 형태로 순차 목록의 한 형태를 뜻합니다. 원소의 삽입은 뒤(rear)에서 이루어지고 삭제는 앞(front)에서 이루어지는 자료 구조를 뜻합니다. 메모리에 적용할 경우 큐는 선입선출 방식을 뜻합니다. 이 때문에 힙과 큐를 혼동해서 사용하기도 합니다. 의미는 같지만 큐는 자료 구조론에서 사용하는 용어고, 힙은 메모리 관련 용어로 사용한다고 보면 됩니다.

데크(Deque)는 Double Ended QUEue의 줄임말로 스택과 큐의 동작 방식을 복합한 방식입니다. 자료 구조에서 선형구조의 목록을 뜻하는 용어로 목록의 양 쪽 끝에서 삽입과 삭제가 가능한 방식입니다.

데크는 입출입 형태에 따라서 한 쪽을 제한할 수 있습니다. 입력 제한 데크라는 방식은 scroll이라고 하는데, 삽입(input)은 목록의 한 쪽 끝에서 이루어지고, 삭제(출력,output)는 목록의 양 쪽 끝에서 이루어지는 방식입니다. 반대로 출력 제한 데크가 있습니다. 출력 제한 데크는 shelf라고 하는데 삽입은 양 쪽 끝에서 이루어지고, 삭제는 목록의 한 쪽 끝에서 이루어지는 방식을 뜻합니다.

출처 : http://www.dal.kr/chair/c/c3201.html

'system > windows' 카테고리의 다른 글

Segmentation 시발점 찾다가  (0) 2011.10.31
110901 긁적긁적  (0) 2011.09.01
dll injection 기초  (0) 2010.09.03
win 명령어  (0) 2010.08.05
컬링 컨벤션 세가지(cdecl,stdcall,fastcall)  (0) 2010.07.07
: