기사 : https://www.dailysecu.com/?mod=news&act=articleView&idxno=44554


 적당히 골라서 분석해 본 샘플이었는데 몇달 전에 발생한 북한 공격으로 추정되는 APT 캠페인의 바이너리였습니다.




블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,

 LD_PRELOAD를 이용하여 고정 인자 함수를 후킹하는 방법의 경우에는 여기저기 설명이 잘 된곳이 많으므로 생략하겠습니다.

이런 블로그 글들을 참고하시면 되겠습니다.


 LD_PRELOAD를 이용하여 함수들을 후킹하는 도중, 인자의 개수가 정해진 것이 아니라 가변적인 함수라면 어떻게 후킹을 해야 하는지 고민을 한 적이 있습니다. 대표적인 예가 printf, sprintf류의 포맷팅 함수들입니다. 이런 함수들은 포맷 문자의 개수에 따라 뒤따라 들어가는 인자의 개수가 계속 늘어날 수 있습니다. 이 포스팅에서는 이런 함수들을 LD_PRELOAD를 이용해 후킹하는 방법에 대해서 설명합니다.


 우선 가변 인자 함수를 만드는 방법에 대하여 알아보아야 합니다. 관련된 내용은 여기에 자세히 잘 정리되어 있습니다.

위 내용을 참고하여 fprintf 함수를 후킹하는 코드를 작성하면 다음과 같이 나오게 됩니다.


1
2
3
4
5
6
7
8
9
int fprintf(FILE *fp, const char *format, ...)
{
    int ret;
    va_list ap;
    va_start(ap, format);
    // 원하는 후킹 행위
    va_end(ap);
    return ret;
}
cs


 위 코드와 LD_PRELOAD를 이용하면 바로 fprintf 함수를 후킹하는 것이 가능합니다. 하지만 아직 완전하지는 않습니다. 문제는 바로 원본 함수인 fprintf 함수를 실행시킬 수가 없기 때문입니다. 이미 스스로 fprintf 함수를 정의해버렸기 때문에 그냥은 libc 함수를 호출할 수 없고, 만약 dlsym(RTLD_NEXT, "fprintf")을 이용해 libc의 fprintf 함수 주소를 가져오면 실행은 시킬 수 있겠지만 fprintf는 말 그대로 가변 인자 함수이기 때문에 인자가 몇 개 들어갈지 알 수 없는 상황에서 사용할 수가 없습니다.


 이럴 때 사용할 수 있는 대체 함수들이 libc에 정의되어 있습니다.

fprintf의 경우에는 vfprintf라고 하며, 이 두 함수의 선언부는 다음과 같습니다.


1
2
int fprintf(FILE *fp, const char * format, ...);
int vfprintf(FILE *fp, const char * format, va_list arg );
cs


 둘 모두 비슷하지만 차이가 있다면 fprintf에서 가변 인자 방식으로 전달받는 인자를 vfprintf는 va_list 타입으로 받는다는 점입니다.

그 점을 제외하고는 두 함수는 하는 일이 동일합니다. 그렇다면 이제 이 vfprintf 함수를 사용하여 후킹하더라도 기존과 똑같이 동작하도록 위의 코드를 수정해보도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
int fprintf(FILE *fp, const char *format, ...)
{
    int ret
    va_list ap;
    va_start(ap, format);
    // 함수 호출 전 원하는 후킹 행위
    ret = vfprintf(fp, format, ap);
    // 함수 호출 후 원하는 후킹 행위
    va_end(ap);
    return ret;
}
cs


 위와 같이 코드를 작성하고 위아래로 함수 실행 전과 후에 원하는 후킹 행위를 추가로 작성하면 원본 함수 실행에 영향을 미치지 않고 후킹을 수행할 수 있습니다. fprintf는 vfprintf라는 함수가 있었고, 이외에도 libc에는 vfscanf, vprintf, vsprintf등 가변 인자 함수에 대응하는 va_list 인자 함수들이 정의되어 있습니다. 이런 함수들을 후킹할 일이 있다면 위 함수들을 찾아서 가져다 쓰면 되겠습니다.

블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,





얼마전(몇달전?) 재밌게 봤던 오징어소녀의 오프닝곡을 듣다 보니 끌려서 퇴근 후 녹음하고 영상 찍어서 간단하게 TV Size로 커버해봤습니다. 곡 자체는 무척이나 간단하지만 멜로디나 박자나 여러모로 기분 좋은 곡이었습니다. Sphere 최고!



블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,


 최근 개인적으로 리눅스 환경에서 C/C++을 혼합해서 쓸 일이 생겼는데, 그때 extern "C"를 사용하면서 알게 된 점들을 작성해 보려고 합니다. 해당 프로젝트는 'https://github.com/skyclad0x7b7/MiniHook' 요놈인데, LD_PRELOAD라는 환경변수를 이용하여 간단하게 함수들을 후킹하여 프로세스가 어떤 행위를 했는지 로깅하는 툴입니다. 윈도우 악성코드 자동 분석 시스템은 많이 만져 봤지만 리눅스는 한번도 해본적이 없었기 때문에 윈도우에서와 비슷한 방식으로 자동 분석이 가능하지 않을까 하여 만들어 보게 되었습니다.



 우선 extern "C"란 무엇인가에 대해 알아보아야 합니다. extern "C"라는 키워드는 C++ 소스에서 선언한 전역 변수나 함수를 C에서 사용해야 할 경우에 쓰입니다. 그 이유는 함수명이나 특정 전역변수명을 '심볼'로 저장하는 방식이 다르기 때문입니다.


1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
 
void test()
{
    printf("Hello World!\n");
}
 
int main()
{
    test();
    return 0;
}
cs


 위의 간단한 소스코드를 예로 들겠습니다. test라는 함수 안에서 Hello World를 출력하고 종료하는 프로그램입니다. 위 소스코드를 각각 gcc와 g++로 컴파일하고, readelf 명령을 이용해 만들어진 바이너리 안의 심볼을 찾아보았습니다.




 gcc로 컴파일한 경우 test라는 함수명이 그대로 출력되지만, g++로 컴파일한 경우 _Z4testv 라는 복잡한 이름으로 변경된 것을 볼 수 있습니다. 이는 C와 C++의 함수 특성에서 차이가 발생하기 때문입니다. C++에는 '함수 오버로딩'이라고 하는 기능이 있는데, 이는 같은 함수명이라고 하더라도 전달받는 타입이 달라진다면 새 함수로 선언 및 사용이 가능한 특징입니다. int func(int a)라는 함수와 int func(double a) 라는 함수를 둘 다 선언하고 정의하더라도 문제가 없게 된다는 것입니다. 하지만 이렇게 했을 시, func라는 함수명만으로 해당 함수들을 구별하는 것이 불가능해집니다. 그래서 C++ 컴파일러들은 각 컴파일러마다 자신들만의 규칙으로 함수 이름을 변경합니다. 이것을 '네임 맹글링(Name Mangling)'이라고 합니다.



각 컴파일러별 네임 맹글링 규칙

Compilervoid h(int)void h(int, char)void h(void)
Intel C++ 8.0 for Linux_Z1hi_Z1hic_Z1hv
HP aC++ A.05.55 IA-64
IAR EWARM C++ 5.4 ARM
GCC 3.x and higher
Clang 1.x and higher[1]
IAR EWARM C++ 7.4 ARM_Z<number>hi_Z<number>hic_Z<number>hv
GCC 2.9xh__Fih__Fich__Fv
HP aC++ A.03.45 PA-RISC
Microsoft Visual C++ v6-v10 (mangling details)?h@@YAXH@Z?h@@YAXHD@Z?h@@YAXXZ
Digital Mars C++
Borland C++ v3.1@h$qi@h$qizc@h$qv
OpenVMS C++ V6.5 (ARM mode)H__XIH__XICH__XV
OpenVMS C++ V6.5 (ANSI mode)CXX$__7H__FIC26CDH77CXX$__7H__FV2CB06E8
OpenVMS C++ X7.1 IA-64CXX$_Z1HI2DSQ26ACXX$_Z1HIC2NP3LI4CXX$_Z1HV0BCA19V
SunPro CC__1cBh6Fi_v___1cBh6Fic_v___1cBh6F_v_
Tru64 C++ V6.5 (ARM mode)h__Xih__Xich__Xv
Tru64 C++ V6.5 (ANSI mode)__7h__Fi__7h__Fic__7h__Fv
Watcom C++ 10.6W?h$n(i)vW?h$n(ia)vW?h$n()v

(출처 : https://en.wikipedia.org/wiki/Name_mangling)


 이렇게 네임 맹글링이 되는 대상은 함수만 있는 것이 아니고, 심볼을 통해 접근해야 하는 전역변수도 똑같이 적용됩니다. 여기서 몇번 테스트를 거치며 깨달은 점이 있는데, C++ 소스에서 선언한 전역변수라고 하더라도 모든 전역변수가 다 네임 맹글링이 되지는 않는다는 점입니다. 


test.h

1
2
3
4
5
6
#include <string>
#include <vector>
 
extern int TestInt;
extern std::string TestString;
extern std::vector<std::string> TestVector;
cs


test.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <string>
#include <vector>
#include "test.h"
 
int TestInt;
std::string TestString;
std::vector<std::string> TestVector;
 
void test()
{
    printf("Hello World!\n");
}
 
int main()
{
    TestInt = 1;
    TestString = "Test";
    TestVector.push_back("Test");
    test();
    return 0;
}
cs


 test.h에서 선언한 전역변수를 test.cpp에서 가져다가 정의하는 소스코드입니다. 위 소스코드를 컴파일한 후 마찬가지로 readelf로 심볼을 확인해보겠습니다.



 실제로 네임 맹글링이 적용된 것은 std::string 타입인 TestString과 std::vector<std::string> 타입인 TestVector뿐이라는 것을 알 수 있습니다. 단순 int형이었던 TestInt의 경우에는 네임 맹글링이 적용되지 않았습니다. 여기서 예측 가능한 것은 C에서도 사용하는 일반적인 타입들(함수 포인터, 기본 타입 변수들)의 전역변수의 경우에는 네임 맹글링이 적용되지 않는다는 것입니다.



(https://stackoverflow.com/questions/17064471/g-name-mangling-of-global-const-variables)

 

 또 이걸 조사하다가 스택오버플로우에서 재밌는 글을 하나 발견했는데, 바로 static 전역변수의 경우는 일반적인 C 타입의 변수라고 할지라도 네임 맹글링을 진행한다고 합니다. 사실 잘 생각해 보면 당연한 것인데, static 전역변수라고 함은 다른 소스코드에서는 접근할 수 없는 변수이므로 다른 소스코드 안에 같은 이름을 가진 다른 변수가 있을 수 있기 때문에 충돌을 피하기 위해 맹글링을 하는 것이 맞습니다. 또한 저 답변의 implicitly static 이라는 말이 뭔가 해서 다시 조사를 해 봤습니다.



(https://stackoverflow.com/questions/3709207/c-semantics-of-static-const-vs-const)


 결론만 말하면, C++에서 전역변수에 static const를 붙이는 것과 const만 붙이는 것은 동일한 동작을 합니다. 즉 const로 선언한 전역변수의 경우에는 extern 키워드를 붙여주지 않는 이상 static 변수로 취급되기 때문에 네임 맹글링이 진행됩니다. 여기까지 정리하면 C++에서 전역변수로 선언한 일반 타입의 변수들의 경우, const 혹은 static 변수에 대해서만 네임 맹글링이 진행된다고 볼 수 있겠습니다.




 어쨌든 네임 맹글링이 되는 조건은 이렇게 된다고 치고, 다시 돌아와서 이런 이유로 네임 맹글링이 일어나기 때문에 C++ 헤더 안에서 test라고 선언한 함수를 C에서 그대로 가져다 쓰려고 하면 네임 맹글링에 의해 변환된 심볼을 알 방도가 없기 때문에 에러가 발생할 수밖에 없습니다. 이를 가능하도록 해주는 것이 extern "C" 키워드입니다. extern "C"를 이용하여 변수나 함수를 선언할 경우 네임 맹글링이 진행되지 않습니다.


test.h

1
2
3
4
5
6
7
8
#include <string>
#include <vector>
 
extern "C" {
    extern int TestInt;
    extern std::string TestString;
    extern std::vector<std::string> TestVector;
}
cs


 위에서 사용한 test.h 헤더 파일에서 변수 선언부를 extern "C"로 감싸준 후 컴파일해보면



 위와 같이 변수명들이 맹글링되지 않고 원본 그대로 출력되는 것을 볼 수 있습니다. 빌드 혹은 실행 시 undefined symbol 에러와 함깨 네임 맹글링이 진행된 심볼이 나타난다면 대부분은 이 부분 문제일 것이므로 앞으로 문제 해결할때 참고하여 고쳐나가야겠습니다.





블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,


 재작년, 그러니까 2017년 11월에 친구 둘과 짧게 도쿄 여행을 다녀온 이후 처음으로 해외여행을 갔다왔습니다. 처음으로 나가는 나홀로 해외여행이었지만 목적지가 이미 한번 간 적이 있는 도쿄인데다 일본어에는 자신이 있었기 때문에 아무런 걱정 없이 길을 나설 수 있었습니다. 이번 여행의 주 목적은 애니메이션 '내 여동생이 이렇게 귀여울리가 없어'의 성지순례(무대탐방)였습니다. 성지순례란 작중에서 배경으로 등장한 장소에 실제로 가보는 것을 뜻하는데, 내여귀의 경우 치바 현과 도쿄가 주 무대였으므로 이번에는 도쿄로 가기로 했습니다. 치바 현도 가야 하지만 시간과 체력상 나중에 가는 걸로 했습니다. 성지순례 관련 내용은 따로 포스트로 올렸으므로 여기서는 여행 자체에 대한 내용만 작성합니다.


성지순례 사진 : https://5kyc1ad.tistory.com/341





















블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,



 이번 2019-02-28 ~ 2019-03-04의 5일동안 일본 도쿄에 다녀왔습니다.

이번 여행의 주 목적은 제목에도 씌여있듯이 내여귀의 성지순례(무대탐방)이었습니다. 본래라면 치바도 성지순례 장소에 포함되어야 하나, 여행 기간이 애매하게 짧고 체력적으로 뒷받침이 되지 않을 것 같아서 치바는 나중에 내청코 성지순례하면서 같이 하기로 했습니다. 도쿄 자체도 워낙 넓어서 일부 지역은 제외하고 크게 아키하바라/시부야/킨시쵸/오시아게/오다이바 + 나리타 공항 총 6가지 지역을 돌기로 하고 계획을 잡았습니다. 이 포스트에서는 실제 다녔던 시간 순서별 지역의 성지순례 사진 및 애니메이션 스크린샷을 첨부하며, 구체적인 여행 내용은 다른 포스트에서 작성하겠습니다.




※ 성지순례 글의 특성상 스포일러가 대량 포함되어 있습니다. 주의하시기 바랍니다.



성지순례는 위의 지도를 참고하였습니다.


























'Hobby > 해외여행' 카테고리의 다른 글

[190228-190304] 4박 5일 도쿄 여행  (0) 2019.03.05
토요코인 클럽카드 발급  (0) 2019.01.06
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,




 TAB : Saki Achiga-hen - FriendShip.gp

TAB(PDF) : Saki Achiga-hen - FriendShip.pdf



 처음으로 청음으로 따본 곡입니다. 멜로디도 무척 단순하고 진짜 어려운 앞부분은 쏙 잘라먹고 메인 멜로디만 쳐서 무척 간단하게 딸수 있었습니다. 역시 사키의 진짜 주인공은 토키였던 것이다...

블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,



[한빛미디어 출판, 64비트 멀티코어 OS 원리와 구조]


 이전에 이 책을 이용하여 OS 개발을 해보려고 생각했다가 이미 cygwin이나 binutils등의 버전이 달라져서 제대로 개발 환경을 구현하지 못해 버그가 무척 많이 발생했기 때문에 반쯤 포기하고 있었습니다. 그러던 중 이 책의 저자이신 한승훈님께서 개발 환경이 모두 구축된 VM을 세팅하여 공유하고 계셨다는 사실을 알게 되었습니다.



[오오 그저 빛 오오]


 해당 원글의 주소는 여기입니다. http://jsandroidapp.cafe24.com/xe/8920


 압축을 푼 이후 VirtualBox를 이용하여 실행 가능하며, 기본적으로 1-Core RAM 2GB로 설정되어 있어서 좀 더 원활한 개발 환경을 위해 저는 2-Core에 RAM 4GB로 늘려주었습니다. OS는 Windows XP였습니다.


 마침 책도 회사에서 생일에 지원받은 상품권을 이용해 두권 모두 사두었기 때문에 차근차근 진행해 나가면서 정리하고 진행상황을 작성해보려고 합니다. 블로그에 글을 남기는것도 이렇게 공개된 곳에 작성하면 나태해지지 않고 계속할 수 있을 것이라고 생각했기 때문입니다. :)


 어쨌든 이 VM 이미지 하나로 모든 개발환경의 준비는 끝났지만, 위 링크의 글에도 나와있다시피 QEMU의 경우 가상머신 내에서 동작시키면 상당히 속도가 느리고 키보드/마우스 입력이 제대로 되지 않는 문제가 있으니 메인 OS에 설치해두는게 좋겠습니다. QEMU는 여기에서 다운로드 및 설치할 수 있습니다. 이제 진행한 내용들을 정리하겠습니다.




 [운영 모드]


 x86-64 프로세서에는 크게 다섯 가지 운영 모드가 있고, 각각은 다음과 같습니다.


- 리얼 모드 : 최대 1MB의 주소 공간을 지원하며 16비트 모드로 동작함. 전원이 켜지거나 리셋되면 항상 이 모드로 진입하며, BIOS의 여러 기능들을 사용할 수 있음.

- 보호 모드 : 최대 4GB의 주소 공간을 지원하며 32비트로 동작함. 세그먼트, 페이징, 보호, 멀티태스킹 등의 기능을 하드웨어적으로 제공함. 

- IA-32e 모드 : 최대 16EB의 주소 공간을 지원하며 32비트 호환 모드, 64비트 모드의 두 가지 서브모드로 동작함.

- 시스템 관리 모드 : 전원 관리, 하드웨어 제어 등 특수 기능을 제공함.

- 가상 8086 모드 : 보호 모드 내부에서 가상의 환경을 설정하여 리얼 모드처럼 동작함.


 여기서 리얼 모드 및 보호 모드에 관해서는 '성공과 실패를 결정하는 1%의 Windows 구조와 원리' 책을 읽으면서 공부하여 정리했던 내용이 있었습니다. GDT와 LDT 관련하여 의문점이 남은 상태로 찝찝하게 글을 마무리했었는데 진행하면서 이 부분에 대해서도 이해가 가능하면 좋겠네요.


[운영 모드 전환 다이어그램]


 각각의 운영 모드는 위와 같은 과정을 통해 다른 모드로 전환될 수 있습니다.


 [레지스터]


운영 모드에 따라 사용하는 레지스터의 종류도 달라지는데, 크게 16비트 레지스터, 32비트 레지스터, 64비트 레지스터로 나타낼 수 있습니다. 다만 GDTR(Global Descriptor Table Register)이나 IDTR(Interrupt Descriptor Table Register) 등 특수한 목적을 지닌 레지스터는 다른 크기를 갖습니다. 범용 레지스터의 용도와 크기, 명칭 등은 이미 대체로 알고 있으므로 다른 블로그의 링크로 대체합니다.


※ PC에 연결된 디바이스를 제어할 때 I/O 어드레스를 지정할 수 있는 어드레스는 DX 레지스터 뿐입니다. 이처럼 범용 레지스터가 특수한 용도로 사용되기도 합니다.


 특이한 점은 IA-32e 시스템의 64비트 서브모드의 경우 64비트 모드이므로 어드레스의 크기가 64비트라 Insturction Pointer인 RIP 레지스터는 64비트 크기이지만, 기본 오퍼랜드 크기는 32비트로 고정이기 때문에 RIP 레지스터에 대한 상대 어드레스로의 접근은 RIP±2GB밖에 되지 않고 그를 초과하는 범위에 접근할 때는 무조건 jmp 명령어를 사용해야만 접근이 가능하다는 점입니다. 32비트 오퍼랜드로는 최대 4GB까지 표현이 가능하므로 음수/양수로 각각 2GB씩밖에 상대 참조가 가능한 것입니다.


 세그먼트 레지스터(Segment Register)는 16비트 레지스터로 어드레스 영역을 다양한 크기로 구분하는 데에 사용됩니다. 운영 모드에 따라 역할이 조금씩 달라지는데, 리얼 모드에서는 단순히 고정된 크기의 영역을 지정하기만 하지만 보호 모드와 IA-32e 모드에서는 접근 권한, 세그먼트의 시작 주소와 크기 등을 지정하는데에 사용되기도 합니다. 각 세그먼트 레지스터의 역할은 다음과 같습니다.


- CS : 코드 영역을 가리키는 레지스터로 점프 명령이나 인터럽트 관련 명령으로만 값을 변경 가능

- DS : 데이터 영역에 접근할 때 암시적으로 사용됨

- ES : 문자열과 관련된 작업을 처리할 때 암시적으로 사용됨

- FS/GS : DS/ES 레지스터와 함께 데이터 영역을 가리키는 레지스터로, 데이터 영역에 접근할 때 DS 레지스터 이외의 세그먼트 레지스터를 사용할 시 각각의 세그먼트 레지스터 접두사를 사용해야 함

- SS : 스택 영역을 가리키는 레지스터로, SP/BP 등 스택 관련 레지스터를 통해 스택에 접근할 때 암시적으로 사용됨


 컨트롤 레지스터(Control Register)는 운영 모드를 변경하고 현재 운영 중인 모드의 특정 기능을 제어하는 레지스터입니다. 각 컨트롤 레지스터의 역할은 다음과 같습니다.


- CR0 : 운영 모드를 제어하는 레지스터. 리얼 모드에서 보호 모드로 전환하는 역할 및 캐시, 페이징 기능 등을 활성화시키는 역할을 함

- CR1 : 프로세서에 의해 예약된 레지스터

- CR2 : 페이지 폴트 발생 시 페이지 폴트가 발생한 선형 주소가 저장되는 레지스터

- CR3 : 페이지 디렉터리의 물리 주소와 페이지 캐시에 관련된 기능을 설정하는 레지스터

- CR4 : 페이지 크기 확장, 메모리 영역 확장 등의 기능을 활성화하고 프로세서에서 지원하는 각종 확장 기능을 제어하는 레지스터

- CR8 : 태스크 우선순위 레지스터의 값을 제어하는 레지스터. 프로세스 외부에서 발생하는 인터럽트를 걸러주는 필터 역할을 함. IA-32e 모드에서만 접근 가능.



 [메모리 관리 기법]

- 세그먼테이션(Segmentation) : 세그먼트 레지스터를 이용하여 원하는 크기만큼 메모리를 나누어 사용

- 페이징(Paging) : CR3 레지스터에 페이지 디렉터리라는 자료구조의 물리 주소를 설정하여 일정 크기만큼 메모리를 나누어 사용


 리얼 모드에서의 메모리 관리 기법

 위에 작성한 바와 같이 리얼 모드는 최대 1MB까지 주소 공간을 사용합니다. 이 모드에서는 세그먼테이션만 지원하며 크기는 64K로 고정입니다. 메모리에 접근할 때 사용하는 범용 레지스터와 세그먼트 레지스터의 크기는 모두 16비트인데 주소 공간을 1MB까지 지원하는 이유는, 세그먼트 레지스터의 값에 0x10을 곱한 값에 범용 레지스터의 값을 더하여 접근하기 때문입니다. 

 예를 들어, FS가 0x1000이고 범용 레지스터가 0x1234라고 한다면 FS의 값인 0x1000에 0x10을 곱하여 0x10000에 범용 레지스터의 값인 0x1234를 더합니다. 최종적으로 0x11234 주소에 접근하게 됩니다.  16비트의 최댓값은 (2^16)-1이고 여기에 0x10을 곱한 후 범용 레지스터의 값까지 더하면 정확히 1MB 크기 내의 주소에 접근이 가능하게 되는 것입니다.


 보호 모드에서의 메모리 관리 기법

- 디스크립터 : 메모리 영역의 정보를 저장하는 자료구조. 세그먼트에 대한 정보를 나타내는 디스크립터를 '세그먼트 디스크립터' 라고 함.

[세그먼트 디스크립터 (출처 : https://en.wikipedia.org/wiki/Segment_descriptor)]


 보호 모드에서는 세그먼테이션과 페이징 기법을 모두 사용합니다. 다만, 여기에서는 세그먼트 레지스터가 직접적으로 메모리 주소를 가리키지 않고 세그먼트 디스크립터 자료구조의 Offset을 가리킵니다. 이를 따라서 레지스터의 명칭도 세그먼트 레지스터에서 세그먼트 셀렉터로 변경되었습니다. 세그먼트 디스크립터들은 메모리상에 위치하는 자료구조의 일종으로 GDT(Global Descriptor Table)이라고 불리는 곳에 모여 있습니다. GDT는 연속된 디스크립터의 집합으로, 최대 8192개의 디스크립터를 포함할 수 있는 테이블 형태의 자료구조입니다. 프로세서는 원하는 디스크립터를 참조하기 위해 GDT의 시작 주소와 크기를 저장하는 구조체의 주소를 담는 GDTR 레지스터를 이용합니다. 선형 주소는 리얼 모드에서와 같은 방식으로 세그먼트 디스크립터의 베이스 어드레스에 범용 레지스터의 값을 더하여 구하지만, 범용 레지스터의 값이 세그먼트 디스크립터에 정의되어 있는 세그먼트의 크기를 넘어설 경우에는 예외를 발생시켜 오류가 발생했음을 알립니다.


 위의 세그먼테이션을 통해 찾아낸 선형 주소의 경우 페이징 기법이 사용되지 않는다면 리얼 모드에서와 같이 물리 메모리와 1대 1로 매칭됩니다. 페이징은 물리 메모리를 페이지(Page)라고 불리는 일정한 크기로 나누고, 선형 주소화 실제 물리 주소를 나눠 놓은 페이지로 연결하는 방식을 말합니다. 페이징을 이용하면 실제 물리 메모리 크기보다 더 큰 영역의 선형 주소도 물리 페이지를 통해 연결하기만 하면 사용 가능하므로 주소 공간을 훨씬 더 넓게 사용할 수 있는 장점이 있습니다(* 가상 메모리의 원리). 또한 프로세스끼리 공유하는 메모리도 한 물리 페이지를 여러 선형 주소에 연결하는 것으로 간단하게 해결이 가능합니다.


[페이징 사용 시 선형 주소] 


 4KB 크기의 페이지로 나누는 3단계 페이징을 사용할 경우 선형 주소는 디렉터리/테이블/오프셋으로 이루어지며, 물리 메모리를 4KB 페이지로 나누어서 관리합니다. 4바이트인 선형 주소 내에서 0~11비트는 4KB 크기인 페이지 내부의 물리 주소를 나타내기 위해서 사용되며, 나머지 디렉터리와 테이블 값은 페이지 디렉터리와 페이지 테이블에 있는 엔트리의 Offset을 가리킵니다. 페이지 디렉터리의 시작 주소는 위에서 언급했던 CR3 컨트롤 레지스터에 저장되어 있습니다.



[페이지 디렉터리 엔트리 (출처 : https://wiki.osdev.org/Paging)]



[페이지 테이블 엔트리 (출처 : https://wiki.osdev.org/Paging)



 실제 메모리 주소를 찾는 과정은 다음과 같이 이루어집니다.


[페이징 주소 참조 (출처 : https://wiki.osdev.org/Paging)]


1. CR3 레지스터를 참조하여 페이지 디렉터리의 시작 주소를 찾습니다.

2. 선형 주소의 페이지 디렉터리 인덱스를 이용해 원하는 페이지 디렉터리를 찾고, 내부의 디렉터리 엔트리 값을 찾습니다.

3. 디렉터리 엔트리를 이용해 페이지 테이블의 시작 주소를 찾습니다.

4. 선형 주소의 페이지 엔트리 인덱스를 이용해 원하는 페이지 테이블을 찾고, 내부의 테이블 엔트리 값을 찾습니다.

5. 테이블 엔트리를 이용해 4KB 크기 페이지의 물리 어드레스를 구하고, 그곳에 선형 주소의 오프셋 값을 더해 실제 물리 주소로 변환합니다.


 IA-32e 모드의 메모리 관리

 IA-32e 모드는 32비트 호환 모드 및 64비트 모드로 동작하는데, 32비트 호환 모드의 경우는 보호 모드와 똑같이 작동합니다. 64비트 모드로 동작할 경우 말 그대로 64비트이므로 사용 가능한 최대 어드레스는 2^64인 16EB나 되는 크기의 주소까지 사용이 가능합니다. 64비트 모드로 동작한다고 하더라도 보호 모드와는 큰 차이는 없고, 주소 공간이 확장되면서 약간의 차이가 생겼을 뿐입니다.  


 첫 번째 차이는 세그먼트 디스크립터에 설정된 베이스 어드레스와 그 크기에 관계 없이 모든 세그먼트가 베이스 어드레스는 0, 크기는 64비트 메모리 전체로 설정된다는 점입니다. 즉, 사실상 64비트 모드에서는 세그먼테이션 기법을 사용하지 않게 되었다고 봐도 무방합니다. 따라서 기존에 개발했던 32비트 OS가 세그먼테이션을 이용해 커널 및 유저 영역을 구분하고 있었다면 이는 IA-32e 모드에서는 유효하지 않게 되었으므로 페이징이나 다른 방식을 고려해야 합니다.

 두 번째 차이는 호환 모드와 64비트 모드의 구분을 위해 코드 세그먼트 디스크립터에 L 필드라는 값이 추가된 것입니다(위의 세그먼트 디스크립터 그림 참조). 이 필드를 1로 설정하면 64비트 모드로, 0으로 설정하면 32비트 호환 모드로 동작합니다. 


 IA-32e 모드의 페이징은 보호 모드와는 달리 주소 공간이 64비트로 늘어났기 때문에 물리 주소 확장(PAE: Physical Address Extension)이 기본으로 활성화됩니다. 또한 기존의 4KB 크기의 3단계 페이징이 5단계로 늘어납니다. 이를 위해 새로 페이지 맵 레벨 4 테이블(PML4)과 페이지 디렉터리 포인터 테이블(PDPT)이 새로 생겼고, 이는 보호 모드에서 설명했던 다른 테이블과 같은 방식으로 참조가 이루어집니다.


[IA-32e 모드의 페이징 (출처 : http://egloos.zum.com/miooim/v/57175)]


  선형 주소의 크기가 64비트로 늘어난 만큼 늘어난 공간에 PML4와 디렉터리 포인터 값을 추가로 넣었습니다. 기존과 마찬가지로 CR3→PML4->디렉터리 포인터 엔트리→페이지 디렉터리 엔트리→페이지 테이블 엔트리→물리 주소 순서대로 참조를 진행합니다. 여기서 선형 주소의 48~63번째 비트가 부호 확장으로 채워진 것을 볼 수 있는데, 그렇다고 2^48의 주소를 사용할 수 있는것이 아니라 프로세서에 따라 최대 2^40까지의 물리 메모리만을 사용 가능합니다.


[IA-32e 모드의 페이지 엔트리 (출처 http://egloos.zum.com/miooim/v/57175)]


 64비트로 늘어난 어드레스로 인해 IA-32e 모드의 페이지 엔트리의 크기는 8바이트로 늘어났습니다. 하위 4바이트는 보호 모드와 같은 구조이며, 상위 4바이트에는 베이스 어드레스와 예약된 영역, 임의 사용 가능한 영역, EXB라는 값으로 구성됩니다. 이중 EXB 필드는 해당 페이지에서 명령어가 실행되는 것을 막을 수 있는 필드로, 이 값을 이용하여 데이터 영역에서 명령어가 실행되는 것을 막을 수 있어 더욱 안전한 OS를 만들 수 있습니다. (Windows의 DEP나 Linux 계열의 NX와 같은 메모리 권한 계열 미티게이션 비슷한 모양)



여기까지 '64비트 멀티코어 OS 원리와 구조' 3장의 내용이었습니다. 다행히도 이전에 메모리 세그먼테이션이나 페이징에 대해 약간 공부한 적이 있어서 이해하기 그렇게 어렵지는 않았습니다. 틈나는대로 한번씩 읽으면서 자신의 지식으로 만들 필요가 있어 보입니다.

블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,


 후우카라는 작품 자체는 사실 잘 모르고 있었는데, 유튜브에서 우연히 듣게 된 이 노래가 너무 좋았기 때문에 현재 원서로 구매해서 읽어보고 있습니다. 2~3권까지 읽다가 잠시 내려놨는데 빠른 시일 내로 어서 다시 읽기 시작해야겠네요. 케이온이나 뱅드림같은 모에계 밴드물은 아니고 나름 진지하게 음악하는 고교생들의 청춘 성장 밴드물이라고 할 수 있겠습니다.


 Wings of Light라는 제목의 이 노래는 '후우카' 완결 기념으로 제작된 특별곡으로, 실제 '후우카' 애니메이션에서 주역 '아키츠키 후우카' 역을 맡으신 성우 Lynn님께서 불러주셨습니다. 여기에서 음원 및 가사를 제공하고 있으며 상업적 이용이 아니라면 마음껏 사용이 가능합니다. 일어 가사의 출처도 저곳임을 밝힙니다. 나중에 꼭 기타로 쳐보고 싶은 곡입니다.






Wings of light


작곡/WEST GROUND 작사/세오 코우지 노래/Lynn


息を止めたまま ずっと 走って行けるかなんて

이키오 토메타 마마 즛토 하싯테이케루카 난테

숨을 멈춘 채로 계속 달려갈 수 있을까 라며


くだらない事試したくなっただけさ

쿠다라나이 코토 타메시타쿠 낫타 다케사

시시한 것을 시험해보고 싶어졌을 뿐이야


僕らを急かすキミの瞳に映る 空に響いたんだ

보쿠라오 세카스 키미노 히토미니 우츠루 소라니 히비이탄다

우리들을 재촉하는 너의 눈동자에 비치는 하늘에 울려퍼졌어


歌声 加速させてく

우타고에 가소쿠사세테쿠

노랫소리 가속해져 가



描(えが)いてた世界 望んでた未来を いつの間にか置き去りにしても

에가이테타 세카이 노존데타 미라이오 이츠노 마니카 오키자리니 시테모

그려왔던 세계, 바랐던 미래를 어느새 홀로 내버려둔대도


心は前に向かっていたんだ 叫んだ想いを 今、ここで翼に変えるから

코코로와 마에니 무캇테이탄다 사켄다 오모이오 이마, 코코데 츠바사니 카에루카라

마음은 앞을 향하고 있었어, 외친 마음을 지금, 여기서 날개로 바꿀 테니까


二度と戻らない日々なんて あるわけないって

니도토 모도라나이 히비난테 아루와케 나잇테

두번 다시 돌아오지 않을 나날 따위 있을 리가 없다고


強く 願うよ 聞き飽きた常識に抗って

츠요쿠 네가우요 키키아키타 쵸우시키니 아라갓테

강하게 빌어 싫증나도록 들었던 상식에 맞서서


I'll give you the Wings of light

I'll give you the Wings of light

I'll give you the Wings of light


キミがいたんだ 風が吹き抜け「今」を始めようか ここで

키미가이탄다 카제가 후키누케 「이마」오 하지메요우카 코코데

네가 있었어, 바람이 지나가는 「지금」을 시작해보자, 여기서



後悔の数なんて 全然 覚えてるわけないけど

코카이노 카즈난테 젠젠 오보에테루 와케 나이케도

후회의 횟수따위 전혀 기억하고 있을리 없지만


あの日からずっと時間(トキ)が止まったままで

아노 히카라 즛토 토키가 토맛타 마마데

그 날부터 쭉 시간이 멈춘 채로


迅(はや)る鼓動にキミの想いが積もり 空に響いたんだ

하야루 코도우니 키미노 오모이가 츠모리 소라니 히비이탄다

빨라지는 고동에 너의 마음이 쌓여 하늘에 울려퍼졌어


歌声 加速させてく

우타고에 카소쿠사세테쿠

노랫소리 가속해져 가


失った世界 壊れたあの夢も 全て届くことのない明日(あした)

우시낫타 세카이 코와레타 아노 유메모 스베테 토도쿠 코토노 나이 아시타

잃어버린 세계, 부서진 그 꿈마저 전부 닿을 일 없는 내일


ずっとただ立ち止まってるくらいなら 叫んだ想いを 今、ここで翼に変えるんだ

즛토 타타 타치도맛테루 쿠라이나라 사켄다 오모이오 이마, 코코데 츠바사니 카에룬다

계속 그저 멈춰 있을 뿐이라면, 외친 마음을 지금, 여기서 날개로 바꾸는 거야


二度と戻らない日々なんて あるわけないって

니도토 모도라나이 히비난테 아루와케 나잇테

두번 다시 돌아오지 않을 날들 따위 있을 리가 없다고


強く 願うよ 打ち寄せる言い訳に抗って

츠요쿠 네가우요 우치요세루 이이와케니 아라갓테

강하게 빌어 밀려드는 변명에 맞서며


I'll give you the Wings of light

I'll give you the Wings of light

I'll give you the Wings of light


僕がいたんだ 風が吹き抜け 「今」を始めようか キミと

보쿠가이탄다 카제가 후키누케 「이마」오 하지메요우카 키미토

내가 있었어, 바람이 지나가는 「지금」을 시작해보자, 너와 함께



さぁ 高くそびえる壁を越え いつか目指した永遠(とわ)の果てまでも

사아 타카쿠 소비에루 카베오 코에 이츠카 메자시타 토와노 하테마데모

자아, 높게 솟아오른 벽을 넘어 언젠가 노렸던 영원의 끝까지도


強く蹴って 強く蹴って 今ここで僕らは飛び立つんだ

츠요쿠 켓테 츠요쿠 켓테 이마 코코데 보쿠라와 토비타츤다

강하게 박차서, 힘차게 박차서 지금 여기서 우리들은 날아오르는 거야


怖いモノなんてないから 今声を上げ前に進むんだ

코와이 모노난테 나이카라 이마 코에오 아게 마에니 스스문다

무서운 것 따윈 없으니까 지금 목소리를 높여 앞으로 향하는 거야


もっと遠くずっと遠く 想いをぶつけて生きていたいんだろう

못토 토오쿠 즛토 토오쿠 오모이오 부츠케테 이키테이타인다로우

더 멀리, 훨씬 멀리 마음을 부딪혀 살아가고 싶잖아


見えていたはずの景色は すぐに霞んで消えてしまうけど

미에테이타 하즈노 케시키와 스구니 케슨데 키에테시마우케도

보였을 터인 경치는 바로 희미해져 사라져버리지만


諦めんな 諦めんな 思い出せここにいる意味はなんだ

아키라멘나 아키라멘나 오모이다세 코코니 이루 이미와 난다

포기하지 마, 포기하지 마. 기억해내 지금 여기에 있는 의미는 뭐야


視界滲んだこの夜を 抜けて僕らは明日(あす)に向かうんだ

시카이 니진다 코노 요루오 누케테 보쿠라와 아스니 무카운다

시계(視界)가 번진 이 밤을 빠져나와 우리들은 내일을 향하는 거야


Wings of light! wings of light!

Wings of light! wings of light!

Wings of light! wings of light!


You've made us everything we are today

You've made us everything we are today

You've made us everything we are today



Even without the wind 飛び立てるんだ

Even without the wind 토비타테룬다

Even without the wind 날아오를 수 있어


あの時の僕らの 夢は音もなく消えて もう形を失くしたとしても

아노 토키노 보쿠라노 유메와 오토모 나쿠 키에테 모우 카타치오 나쿠시타토 시테모

그 시절 우리들의 꿈은 소리도 없이 사라져 더는 형체마져 잃었다고 하더라도


I'll come right now let us soar to our new world

I'll come right now let us soar to our new world

I'll come right now let us soar to our new world


輝いてる 埃だらけになったとしても キミの燈(ひ)は消えないから

카가야이테루 호코리다라케니 낫타토시테모 키미노 히와 키에나이카라

빛나는 먼지투성이가 되어버렸다고 해도 해도 너의 빛은 사라지지 않으니까



二度と戻らない日々なんて あるわけないって

니도토 모도라나이 히비난테 아루와케 나잇테

두번 다시 돌아오지 않을 날들 따위 있을 리가 없다고


強く 願うよ 聞き飽きた常識に抗って

츠요쿠 네가우요 키키아키타 쵸우시키니 아라갓테

강하게 빌어 싫증나도록 들었던 상식에 맞서서


I'll give you the Wings of light

I'll give you the Wings of light

I'll give you the Wings of light


キミがいたんだ 風が吹き抜け「今」を始めようか ここで

키미가이탄다 카제가 후키누케 「이마」오 하지메요우카 코코데

네가 있었어, 바람이 지나가는 「지금」을 시작해보자, 여기서





 오역이나 잘못된 점은 댓글로 부탁드립니다.

'Hobby > 노래' 카테고리의 다른 글

Shiggy Jr. - ピュアなソルジャー  (0) 2018.11.09
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,


 단순히 친구랑 밥 먹고 커피 마시고 하면서 찍은 사진을 이렇게 블로그에 올리는건 처음이긴 한데, 일단 무엇이든 기록으로 남겨서 나쁠 건 없다는 생각에 이렇게 글을 올립니다 :D




 가게 앞에서 찍는걸 깜빡해서 네이버 거리뷰에서 가져왔습니다. 낙성대역 8번출구 앞으로 좀 나가면 양옆 다른 건물들에 비해 약간 안쪽으로 들어가있어요. 여기는 학교&회사 선배님이 소개해주셔서 같이 간 이후 맛도 가격도 훌륭해서 자주 가고 있습니다. 글 올린 시점 기준으로 매주 월요일과 화요일은 쉰다고 해요.




 메뉴는 이렇게 있고, 가격은 무척 저렴한 편입니다. 기억상 500원을 추가하여 양 추가를 선택할 수 있다고 알고 있습니다. 음료의 경우 주문할 경우 캔과 함께 얼음컵과 빨대를 갖다줍니다. 피자를 시키면 핫소스도 같이 줘요.


 이날 군대에서 휴가나온 친구와 함께 갔었는데, 저는 위의 오븐미트 스파게티를 시켰습니다. 오븐스파게티라 접시가 무척 뜨거우니 먹을때 데지 않도록 주의해야 합니다.




 함께 주문한 플레인또띠아피자. 스파게티만으로는 조금 아쉽다면 하나 주문해서 같이 먹어도 괜찮습니다. 마늘빵도 주문하면 바삭하게 구워서 갖다줘서 배 채우기 좋더라구요.


 전체적으로 내부 구조가 그렇게 넓은 편은 아니고, 인기는 많은 편이라서 식사시간대에는 대기가 있을 수도 있습니다. 테이크아웃도 된다고 알고 있기는 한데 한번도 해본적은 없네요. 착한 가격과 맛 때문에 자주 찾아가는 맛집입니다 :)




 식사 후에는 근처 커피빈에서 카푸치노를 마셨습니다~





블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

,