PCB (Process Control Block)


 운영체제가 프로세스에 대한 정보를 저장해 놓은 곳으로, 프로세스당 하나씩 1:1로 생성된다.

어떤 프로세스가 Interrupt나 System Call을 만나 다른 프로세스로 작업을 전환하는 것을 Context Switching이라고 하며, 이때 운영체제는 PCB에 실행 중이던 프로세스의 정보를 저장한 후 실행할 프로세스의 정보를 가져와 작업을 수행한다.

부모와 자식 프로세스 사이에도 PCB는 공유하지 않으며 부모든 자식이든 무조건 각 프로세스당 PCB는 1:1로 생성된다.


PCB의 구조는 일반적으로 다음과 같다.




1. Process ID : 프로세스 식별자, PID


2. Process state



 현재 프로세스의 상태를 나타내며 여기에는 생성(create)/준비(ready)/실행(running)/대기(waiting)/완료(terminated)가 있다.


생성(create)       : 프로세스가 생성은 되었지만 아직 운영체제에 의해 실행은 불가능한 상태

준비(ready)        : CPU의 할당을 기다리는 상태

실행(running)     : CPU를 할당 받아 실행되는 상태

대기(waiting)      : 실행 중인 프로세스가 어떤 사건(입출력 등)이 발생할때까지 멈추어 있는 상태

완료(terminated) : 프로세스 실행이 완전히 끝나 CPU 할당이 해제된 상태


3. Program Counter : 프로세스가 다음에 실행할 명령어의 주소 저장


4. Registers : CPU 레지스터의 값 저장


5. Memory Information : 해당 프로세스의 주소 공간 등의 데이터 저장


6. Accounting Information : 페이지 테이블, 소유자, 부모, 경과 시간 등 저장


7. I/O Information : 프로세스에 할당된 입출력장치 목록, 열린 파일 목록 등 저장

'Knowledge' 카테고리의 다른 글

NAT와 NAPT의 개념과 원리  (10) 2016.12.01
멀티 태스킹(Multi-Tasking)의 원리  (0) 2016.11.21
[Assembly] Intel x86, Local JMP [0xE9]  (0) 2016.11.07
[BigData] Spark 공부  (0) 2016.10.19
Visual Studio 2008에서 libcurl 사용하기  (0) 2016.09.05
블로그 이미지

__미니__

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

,


http://x86.renejeschke.de/html/file_module_x86_id_147.html


후킹을 하다 보면 1 byte만으로 점프를 해야 하는 일이 생긴다.

주소값 4바이트를 포함한다는 가정 하에 총 5바이트만으로 점프해야 하는데, 이때 Opcode E9짜리 JMP를 사용한다.


사용법은 굉장히 단순한데, 1바이트 Opcode와 4바이트 주소를 써 주면 된다.

물론 주소는 리틀 엔디안으로 넣어야 한다.


하지만 유의할 점이 하나 있는데, E9를 사용한 JMP는 Local JMP이기 때문에 JMP 명령의 주소로부터 상대적인 거리로 점프한다는 것이다.

그래서 절대 주소로 점프하기를 원한다면 따로 계산을 해서 오퍼랜드에 넣어주어야 한다.


계산 공식은 다음과 같다.


(넣을 주소) = (점프할 주소) - (JMP 명령의 주소) - 5


뒤에 5 bytes를 빼주는 이유는 JMP Opcode (1 byte) + Operand (4 bytes) 로 총 5바이트가 더해지기 때문이다.



'Knowledge' 카테고리의 다른 글

멀티 태스킹(Multi-Tasking)의 원리  (0) 2016.11.21
PCB (Process Control Block)  (0) 2016.11.14
[BigData] Spark 공부  (0) 2016.10.19
Visual Studio 2008에서 libcurl 사용하기  (0) 2016.09.05
RC4 Stream Cipher  (0) 2016.07.19
블로그 이미지

__미니__

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

,

[BigData] Spark 공부

Knowledge 2016. 10. 19. 16:32
spark.html

Basic of Spark

이하의 내용은 ‘Learning Spark’ 책의 3장까지 공부한 내용을 바탕으로 작성한 글입니다.
소스코드는 책의 것을 일부 인용했습니다.

소스는 모두 Python으로 작성됩니다.


About Spark

Spark는 분산 데이터 연산/처리 플랫폼이다.
기존에 Hadoop은 일괄 데이터 처리에 효율적이었으나 현재는 실시간으로 증가하는 빅데이터를 처리해야 하기에 Hadoop의 맵리듀스 프레임워크는 사용하기 힘들다.

맵리듀스 프레임워크는 실시간 데이터 처리 과정에서 많은 트래픽과 디스크 I/O를 요구할 수 있고, 맵->리듀스로 이어지는 2단계 구조로 데이터를 프로세싱하기 때문에 반복 작업이나 산발적으로 일어나는 데이터 연산/처리에는 부적합하다.


Spark는 맵리듀스 모델을 대화형 명령어 쿼리나 스트리밍 처리가 가능하도록 확장하였다.
Spark는 기본적으로 인메모리 기반으로 데이터를 연산하기 때문에 디스크 기반 연산을 수행하는 맵리듀스보다 훨씬 뛰어난 성능을 보이지만 이를 디스크에서 돌린다고 하더라도 맵리듀스보다는 뛰어난 성능을 보여 준다.


Spark는 Scala 기반으로 개발되었으며 Python, Scala, Java, SQL 등의 라이브러리를 내장해 지원한다.
다른 빅데이터 툴들과도 연계가 잘 되는데, Spark는 Hadoop 클러스터 위에서 실행할 때 특히 좋은 성능을 보인다.
그렇다고 Hadoop을 꼭 필요로 하는 것이 아니라 단순히 Hadoop API를 사용하는 저장 시스템을 지원할 뿐이다.



RDD 다루기

모든 Spark 애플리케이션은 클러스터에서 다양한 병렬 연산을 수행하는 드라이버 프로그램으로 구성된다.
드라이버 프로그램들은 연산 클러스터에 대한 연결을 나타내는 SparkContext 라는 객체를 통해 Spark에 접속하는데, Python이나 Scala로 셸을 통해 접속할 경우 자동적으로 sc라는 변수에 만들어지므로 따로 만들 필요는 없다. 단일 프로그램으로 Spark를 다룰 때는 다음과 같이 SparkContext를 만들어 줘야 한다.

from pyspark import SparkConf, SparkContext

conf = SparkConf().setMaster("local").setAppName("My App")
sc = SparkContext(conf = conf)

SparkContext를 이용하면 이것으로 RDD라는 것을 만들어낼 수 있다.
RDD는 Resilient Distributed Dataset의 약자로, 단순하게는 분산되어 존재하는 데이터 요소들의 모임이다.
RDD는 여러 개의 파티션으로 이루어져 있으며 개수는 사용자가 직접 지정이 가능하다. 파티션의 개수에 맞춰서 병렬 연산을 수행하기 때문에 많은 파티션으로 나눠져 있으면 빨라지는 것은 사실이지만, 너무 많은 파티션으로 나누는 것도 효율이 좋지 않을 수 있다. 이를 효율적으로 적용하는 것은 개발자의 몫이다.

이미지
(출처 : http://ourcstory.tistory.com/147)


위 이미지를 보면 코어가 3개인 PC에서 파티션을 4개 만들었을 때와 3개 만들었을 때 작업 처리에 걸리는 시간을 나타내고 있다.

Spark는 Hadoop API를 지원하기 때문에 HDFS, Local File System, Cloud Service 등에서 데이터를 받아와 RDD를 만들 수 있다.
또한 파일을 읽어서 RDD를 만들 수도 있으며 parallelize 함수에 직접 데이터를 입력하여 RDD로 변환하는 것도 가능하다.

1) parallelize 함수 사용

다음과 같이 sc의 parallelize 함수에 데이터를 인자로 넘겨 주면 그것으로 RDD를 만들 수 있다.

sc = SparkContext(conf = conf)
myRDD = sc.parallelize([1, 2, 3, 4])

2) 외부 데이터 사용

대표적으로 textFile 함수를 이용해 외부의 데이터를 받아와 RDD를 만들 수 있다.

sc = SparkContext(conf = conf)
myRDD = sc.textFile("Path_of_File")


RDD가 일단 한 번 만들어지면 이를 수정하는 것은 불가능하다.
RDD는 두 가지 타입의 연산을 지원하는데, 트랜스포메이션(Transformation)액션(Action)이다.
트랜스포메이션은 연산 결과 값으로 새로운 RDD를 리턴하고, 액션은 RDD를 제외한 데이터 타입을 리턴한다.
여기서 트랜스포메이션이 연산 결과 값으로 새로운 RDD를 리턴한다고 했는데, RDD는 수정이 불가능하다고 한 이유가 여기에 있다.
RDD가 수정되는 것이 아닌, 새로운 RDD를 하나 더 만들어서 변경된 값으로 채워 넣는 것이다.

Spark에서 자주 사용하는 트랜스포메이션과 액션은 다음과 같은 것들이 있다.

Transformations & Actions

이미지
(출처 : http://dirtysalt.github.io/spark-rdd-paper.html)
더 자세한 내용은 여기 참고



연산 처리 방식

Spark는 트랜스포메이션과 액션을 처리할 때 늘 여유로운 방식(lazy evaluation)으로 액션이 실행되는 시점에 처리한다.
예를 들어, sc.textFile(…) 을 실행하여 나온 RDD에 filter() 를 실행해 새로운 RDD를 만들고, 그 RDD에 first() 라는 Action을 수행하는 다음과 같은 코드를 생각해 보자.


lines = sc.textFile("README.md")
filteredLines = lines.filter(lambda line: "Python" in line)
print filteredLines.first()


일반적으로 생각해 보면 sc.textFile(…) 에서 이미 모든 파일을 읽어서 버퍼에 내용을 저장했을 것이다.
이후 filter() 를 수행하면서 그 많은 줄들을 전부 필터링했을 것이고 마지막으로 first()에서 가장 첫 번째 줄을 반환했을 것이다.
이는 매우 비효율적인 데이터 처리 방식이다. 결국 필요한 것은 “Python”이라는 문자열이 들어가는 첫 문장인데 저 방식을 그대로 사용하면 파일 전체를 읽어서 전체를 필터링하게 된다.


그래서 Spark는 액션 연산인 first()가 나오기 전까지의 트랜스포메이션은 meta에 저장해 두고 액션이 실행될 때 그에 맞추어서 트랜스포메이션을 실행한다. “Python”이라는 문자열이 나올 때까지만 파일을 읽고, 찾으면 바로 중단 후 반환하는 식으로 실행하는 것이다. 확실히 파일 전체를 읽는 것보다는 훨씬 효율적이다.


이렇게 연산을 실행하면 매우 효율적으로 보이지만 문제점이 하나 있다.
Spark는 액션 연산을 실행할 때마다 트랜스포메이션 연산을 다시 실행하므로 트랜스포메이션을 실행한 후 생성된 같은 RDD로 연산을 연속해서 수행할 경우 이미 트랜스포메이션을 통해 RDD를 한 번 생성했음에도 불구하고 같은 RDD를 계속해서 새로 생성하게 된다.
다시 예를 들어 다음과 같은 코드를 보자.


lines = sc.textFile("README.md")
filteredLines = lines.filter(lambda line: "Python" in line) # Transformation
print filteredLines.first()   # Action
print filteredLines.collect() # Action


비슷한 코드지만 마지막에 액션을 한 번 더 하고 있다.
이렇게 트랜스포메이션 이후 반복적으로 액션을 할 경우 여유로운 방식에 의해 lines.filter()는 3번째 줄에서 한 번, 4번째 줄에서 한 번 더 실행된다.
여기서 보기에는 별거 아닌 것처럼 보일지도 모르지만 데이터를 여러 번 수행하는 반복 알고리즘에 대해서는 매우 무거운 작업일 수 있다.

이런 반복 작업을 방지하기 위한 것이 persist() 라는 함수로, RDD를 메모리에 저장한 후 이후 해당 RDD를 사용할 때 저장된 RDD를 사용하도록 하는 것이다. 이를 영속화(Caching)라고 부른다. 메모리에 저장된 RDD는 LRU(Least Recently Used : 최근에 사용된 것들은 남겨 두고 오래된 것들을 버리는 알고리즘)에 의해 메모리가 가득 차거나 따로 해제하지 않는 이상 자동으로 해제되지 않으므로 프로그램 종료 전에 반드시 unpersist() 를 이용해 메모리에서 해제해야 한다.


lines = sc.textFile("README.md")
filteredLines = lines.filter(lambda line: "Python" in line)
filteredLines.persist(StorageLevel.DISK_ONLY)
print filteredLines.first()
print filteredLines.collect()
filteredLines.unpersist()


persist()는 5종류의 인자를 받을 수 있는데 이는 각각 다음과 같은 특징을 갖는다.



 레벨

 공간 사용

 CPU 사용 시간

 메모리에 저장

 디스크에 저장

 비고

 MEMORY_ONLY

 높음

 낮음

 예

 아니오

 

 MEMORY_ONLY_SER

 낮음

 높음

 예

 아니오

 

 MEMORY_AND_DISK

 높음

 중간

 일부

 일부

 

메모리에 넣기에 데이터가 너무 많으면 디스크에 나눠 저장

 MEMORY_AND_DISK_SER

 낮음

 높음

 일부

 일부

 

메모리에 넣기에 데이터가 너무 많으면 디스크에 나눠 저장. 메모리에 직렬화된 상태로 저장

 DISK_ONLY

 낮음

 높음

 아니오

 예

 



'Knowledge' 카테고리의 다른 글

PCB (Process Control Block)  (0) 2016.11.14
[Assembly] Intel x86, Local JMP [0xE9]  (0) 2016.11.07
Visual Studio 2008에서 libcurl 사용하기  (0) 2016.09.05
RC4 Stream Cipher  (0) 2016.07.19
스트림 암호 (Stream Cipher)  (0) 2016.07.18
블로그 이미지

__미니__

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

,


Visual Studio 2008 환경에서 libcurl을 사용할 일이 생겼다.

그냥저냥 인터넷에 나와 있는 대로 하니 파일 다운로드 받는 위치도 사람마다 다르고, 버전도 달라서 고생을 많이 했다.

다음부터는 이런 고생을 하지 않기 위해, 또는 나와 같은 처지인 사람들을 위해 이렇게 글을 남겨 둔다.


일단 libcurl의 최신 버전은 Visual Studio 2008에서 사용할 수 없다.

따라서 이전 버전을 사용하는 수밖에 없는데, 나는 7.23.1버전을 사용했다.

Debug로 빌드할지 Release로 빌드할지는 사용자 마음대로이므로 이부분은 Debug로 고정해서 서술하겠다.


적용 방법은 다음과 같다.



1. 자신의 VS에 맞는 libcurl을 다운받는다.


https://curl.haxx.se/download/


필자는 7.23.1을 다운받았다.

모든 버전의 libcurl은 여기서 다운받을 수 있다.





2. 다운로드받은 libcurl을 Visual Studio 2008로 빌드한다.


libcurl의 압축을 풀면 내부에 dsw 파일이 존재한다. 이를 VS 2008로 열면 프로젝트가 열린다.

curlsrc와 libcurl의 두 가지인데, 이중 libcurl만 빌드해도 상관없다.

별 이상 없이 빌드가 완료되면 lib\DLL-Debug\ 내부에 libcurld.dll과 libcurld_imp.lib 파일이 생성된다.





3. libcurl을 사용할 프로젝트를 생성하고, 라이브러리를 설정한다.


Project -> Properties -> Configuration Properties -> C/C++ -> Additional Include Directories 에 libcurl 내부의 include 디렉토리를 지정한다.


Project -> Properties -> Configuration Properties -> Linker -> Additional Library Directories 에 libcurl/lib 내부의 DLL-Debug 디렉토리를 지정한다.


Project -> Properties -> Configuration Properties -> Linker -> Input -> Additional Dependencies 에 libcurld_imp.lib를 지정한다.


마지막으로 libcurl/lib/DLL-Debug 내부에 들어 있는 libcurld.dll 파일을 복사하여 <프로젝트 디렉토리>/Debug/ 에 넣는다.


이제 libcurl 사용이 가능해졌을 것이다.







https://curl.haxx.se/libcurl/c/simple.html


이 안에 있는 예제를 빌드해 보자.

다음과 같이 잘 실행된다면 성공이다.



'Knowledge' 카테고리의 다른 글

[Assembly] Intel x86, Local JMP [0xE9]  (0) 2016.11.07
[BigData] Spark 공부  (0) 2016.10.19
RC4 Stream Cipher  (0) 2016.07.19
스트림 암호 (Stream Cipher)  (0) 2016.07.18
사설망-외부망 통신에 대한 공부  (0) 2016.07.02
블로그 이미지

__미니__

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

,

RC4 Stream Cipher

Knowledge 2016. 7. 19. 10:22



RC4는 Rivest Cipher 4의 약자로, 꽤 오래된 스트림 암호이다.

WEP의 암호화 방식으로 사용되었으나, 현재는 취약점이 드러나 WEP는 사용되지 않고 있다.

이 암호의 작동방식을 아주 간략하게 설명하면,


1. Seed를 통해 랜덤 값 생성

2. 랜덤 값과 원본 텍스트를 XOR


이 끝이다.

복호화는 저 과정을 한번 더 반복하면 된다.

별로 어려운 암호도 아니지만, 이런 걸 구현해보는 것은 또 처음이다 보니 인덱싱 문제로 살짝 고생했다.

작성해본 파이썬 코드는 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def KSA(seed):
    S = []
    key = []
    j = 0
    for i in range(0256):
        S.append(i)
        key.append(ord(seed[i % len(seed)]))
 
    for i in range(0256):
        j = (j + S[i] + key[i]) % 256
        S[i], S[j] = S[j], S[i]
    return key, S
 
def PRGA(key, S):
    i, j = 00
    xorKey = []
    for k in range(0256):
        i = (i+1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        xorKey.append(S[(S[i] + S[j]) % 256])
    return xorKey
 
def XOR(xorKey, target):
    ret = []
    for i in range(len(target)):
        ret.append(xorKey[i] ^ ord(target[i]))
    ret = ''.join(map(chr, ret))
    return ret
 
def RC4(text, seed):
    key, S = KSA(seed)
    xorKey = PRGA(key, S)
    return XOR(xorKey, text)
 
seed = "\x01\x02\x03\x04\x05"
text = "Hello World"
 
print "[*] Original Text : " + text
enc = RC4(text, seed)
print "[*] Encoded Text (Hex) : " + enc.encode('hex')
dec = RC4(enc, seed)
print "[*] Decoded Text (Hex) : " + dec.encode('hex')
print "[*] Decoded Text : " + dec
cs


'Knowledge' 카테고리의 다른 글

[BigData] Spark 공부  (0) 2016.10.19
Visual Studio 2008에서 libcurl 사용하기  (0) 2016.09.05
스트림 암호 (Stream Cipher)  (0) 2016.07.18
사설망-외부망 통신에 대한 공부  (0) 2016.07.02
Greedy Algorithm + 회의실 배정  (0) 2016.06.21
블로그 이미지

__미니__

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

,



대칭키 알고리즘의 일종으로, 대칭키를 이용해 의사 난수열을 발생시키고,

이 난수열을 평문에 XOR하는 방식으로 동작하는 암호화 알고리즘.

마찬가지로 복호화 시에는 대칭키로 의사 난수열을 발생시켜 암호문에 XOR하여 평문을 얻어낸다.


(출처 : http://www.ktword.co.kr/abbr_view.php?nav=2&id=955&m_temp1=5541)

'Knowledge' 카테고리의 다른 글

Visual Studio 2008에서 libcurl 사용하기  (0) 2016.09.05
RC4 Stream Cipher  (0) 2016.07.19
사설망-외부망 통신에 대한 공부  (0) 2016.07.02
Greedy Algorithm + 회의실 배정  (0) 2016.06.21
Kernel/User mode  (0) 2016.04.15
블로그 이미지

__미니__

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

,

보통 네트워크 통신을 진행할 때, NAT를 이용하여 공인IP를 사설IP로 나눠서 사용하곤 한다.
(A
클래스에서는 10.~, B클래스에서는 172.16.~, C클래스에서는 192.168.~ 등으로 나뉘는, 그 주소이다.)

OSI 7계층이라는 말을 많이 들어 보았을 것이라고 생각한다.
OSI 7
계층은 통신 계층을 수직적으로 7개의 각각 다른 계층으로 나누어 놓은 것으로,
각 계층을 독립적으로 구성하여 변경이 필요할 시 해당 모듈만을 변경해도 되도록 만든 것이다.


OSI 7계층은 낮은 순서대로 물리데이터 링크네트워크전송세션표현응용 계층으로 구성된다.

OSI 7계층을 좀더 기능별로 압축하여 만든 TCP/IP 계층 구조도 있는데,
이는 낮은 순서대로 네트워크 인터페이스인터넷전송응용 계층으로 구성된다.


TCP로 데이터를 전송하는 통신을 할 때, OSI 7계층 기준으로 세션/표현/응용 계층에 Data가 전달되고
전송 계층의 대표적인 프로토콜인 TCP에 해당 어플리케이션의 Port TCP 통신에 필요한 정보들이 지정되며,
네트워크 계층의 대표적인 프로토콜인 IP에 말 그대로 IP 주소가 지정된다.


한 단계 더 내려가 네트워크 인터페이스 계층까지 내려가 보면 실질적인 통신을 위한 MAC Address 네트워크 계층에서 사용하는 프로토콜에 대한 정보 등을 담고 있다.
그 밑인 물리 계층은 캡슐화 종류, 전체 패킷의 길이 등을 담고 있다.

이해를 돕기 위해 계층의 중요한 저장되는 정보를 연결하여 나타내면 다음과 같다.


세션/표현/응용 : Data
전송 : Dest_port, Src_port
네트워크 : Dest_ip, Src_ip
데이터 링크 : Dest_MAC, Src_MAC


네트워크의 통신에 대해 생각하는 도중, 의문이 든 것이 바로 이 부분이었다.

사설망 내부에서 내 PC가 서버로 보낸 패킷은 네트워크 계층에 다음과 같은 정보가 담겨서 나간다.
네트워크 : Src_ip = “192.168.0.6”, Dest_ip = “8.8.8.8”
이는 와이어샤크로 직접 확인해 봤을 때도 나타난 결과이다.





그런데 우리는 당연하게 생각하고 있는 것이,
우리는 사설 네트워크 내부에 있는데 바깥의 서버와 통신을 할 때는 공인IP를 이용한다는 것이다.
내 패킷이 저대로 전달된다고 가정하면 “8.8.8.8”에서는 내 패킷을 받고, Src_ip “192.168.0.6”였으므로 당연히 저 주소로 Response를 하게 되는데, 조금만 생각해도 될 리가 없다. 사설 네트워크의 주소이기 때문이다.


“8.8.8.8”
과의 통신을 위해서는 사설 네트워크의 주소가 아닌 공인IP를 이용하여 통신해야 한다.

그런데 패킷 구조 어디를 봐도 공인IP로 통신을 하기 위해 공인IP를 저장하는 공간이 없다.

라우터 측에서 네트워크계층의 src_ip 부분을 공인IP로 변경한다고 가정할 수도 있는데, 이렇게 되면 Response 패킷의 dest_ip 부분이 공인IP 주소로 바뀌어야 한다.


하지만 실제로 들어온 패킷을 wireshark를 이용해 잡아본 결과,
dest_ip
에는 사설 네트워크 내부의 내 IP 주소가 들어있다.

이게 가능하기 위해서는 패킷이 PC를 떠나 라우터를 거쳐 서버로 향하는 과정에 라우터의 공인IP 주소를 담는 부분이 패킷에 추가되어야 한다.


또는 다른 방식을 이용하여 어떻게든 공인IP와 사설IP를 모두 저장할 방법이 필요하다.

그런데, 직접 서버에서 사설망 내부에서부터 보내진 패킷을 잡아서 분석해 봤더니

이렇게, 공인IP 주소가 찍혀 있는 것을 볼 수 있었다.


마찬가지로 Response 패킷을 확인해 보니

Dest_ip에 공인IP 주소가 적혀 있다.

이를 통해 내가 보낸 패킷이나 내가 받는 패킷은 라우터를 기점으로 네트워크계층의 프로토콜에 변동이 일어나고,


사설망->외부망 : 사설IP->공인IP

외부망->사설망 : 공인IP->사설IP


형식으로 바뀐다는 것을 알 수 있었다.

그럼 대체 이건 어떻게 작동하는 것일까.
그나마 예측하자면 라우터에 통신 내역이 저장되거나, MAC Address를 보고 거기에 맞춰 IP Address를 넣어주던가, 두가지 가능성이 있는데,
후자같은 경우 데이터 링크 계층의 MAC Address같은 경우 통신의 주체가 바뀔 때마다 바뀌어버리기 때문에 불가능하다.
따라서 전자라는 의미인데, 과연 라우터 내부에서 어떻게 저런 일이 가능한지가 궁금하다.


이 부분은 나중에 더 공부하도록 하자.


공부해서 알아낸 내용을 정리하였다.


'Knowledge' 카테고리의 다른 글

RC4 Stream Cipher  (0) 2016.07.19
스트림 암호 (Stream Cipher)  (0) 2016.07.18
Greedy Algorithm + 회의실 배정  (0) 2016.06.21
Kernel/User mode  (0) 2016.04.15
마이크로/모놀리식 커널 (Micro/Monolithic Kernel)  (0) 2016.04.02
블로그 이미지

__미니__

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

,



Greedy Algorithm



그리디 알고리즘이란 문제의 해를 구하는 데에 있어 매 순간에 최적의 값을 택하는 알고리즘이다.

모든 경우의 수를 전부 체크하지 않기 때문에 이 알고리즘을 통해 최적의 경우를 찾았다고 확신할 수는 없다.

따라서 이 알고리즘을 사용할 때에는 실제로 이 알고리즘이 전체 경우의 수를 고려했을 때에도

최적의 결과를 낼 수 있는지를 꼭 고려해 봐야 한다.



다음은 정올 1370번 문제인 회의실 배정(http://jungol.co.kr/bbs/board.php?bo_table=pbank&wr_id=645&sca=3020)의 풀이를 직접 작성한 것이다.

이 경우, 이전 회의가 끝나지 않으면 다음 회의가 진행될 수 없다는 제약 조건을 이용하여

모든 회의의 종료 시각을 기준으로 오름차순 정렬하고, for문을 이용해 모든 조건을 다 돌면서

다음 회의의 시작 시각이 현재 회의의 종료 시각보다 작은 경우에 값을 저장하고, 나머지는 무시해버리면 된다.

어차피 오름차순으로 정렬되어 있기 때문에 시작 시간이 같은 경우 가장 빨리 끝나는 회의가 가장 앞에 위치한다.



...라는 목적으로 작성한 코드인데, 왜인지 잘 작동하지 않는다.

내 컴퓨터에서는 정상적으로 작동하고 값도 잘 나오는데, 정올에 돌리니 Runtime Error가 나더라...

나중에 확실히 성공하게 되면 수정하도록 하겠다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
 
using namespace std;
 
bool mySortASC(pair<intpair<intint>> i, pair<intpair<intint>> j) {
    return i.second.second < j.second.second;
}
 
int main(int argc, char *argv)
{
    vector<pair<intpair<intint>>> meet;
    vector<int> ret;
    int num, startHour, endHour, N;
    int minTime = 2147483647;
 
    cin >> N;
    for (int i = 0; i<N; i++) {
        cin >> num;
        cin >> startHour;
        cin >> endHour;
        meet.push_back(pair <intpair<intint>>(num, pair<intint>(startHour, endHour)));
    }
 
    sort(meet.begin(), meet.end(), mySortASC);
    ret.push_back(meet[0].first);
    endHour = meet[0].second.second;
    for (int i = 1; i < N; i++) {
        if (endHour <= meet[i].second.first) {
            endHour = meet[i].second.second;
            ret.push_back(meet[i].first);
        }
    }
    
    cout << ret.size() << endl;
    for (int i = 0; i < ret.size(); i++) {
        cout << ret[i] << " ";
    }
    cout << endl;
 
    system("pause");
    return 0;
}
cs


'Knowledge' 카테고리의 다른 글

스트림 암호 (Stream Cipher)  (0) 2016.07.18
사설망-외부망 통신에 대한 공부  (0) 2016.07.02
Kernel/User mode  (0) 2016.04.15
마이크로/모놀리식 커널 (Micro/Monolithic Kernel)  (0) 2016.04.02
libcapstone-dev 설치 방법  (0) 2016.03.12
블로그 이미지

__미니__

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

,

Kernel/User mode

Knowledge 2016. 4. 15. 22:32



 운영체제에는 계층별로 자원에 대한 접근을 제한하거나 허용해 놓은 특권 레벨(Privilege Level)이라는 것이 존재하는데,

이는 Privilege Ring이라고도 부르며 이를 그림으로 나타내면 다음과 같다.



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



 이는 낮은 권한에서 악성코드 등에 의해서 운영체제가 손상되는 것을 방지하고, 각 계층별 할 수 있는 일을 정하여 계층에 대한 역할을 구조화하기 위해서이다. 그림에서 보다시피 Kernel 레벨인 Ring 0부터 User(Application) 레벨인 Ring 3까지 특권 레벨이 존재한다.


 위에서도 언급했다시피 유저 모드와 커널 모드는 자원에 대한 접근에서 그 차이가 발생한다.


 유저 모드에서 실행되는 응용 프로그램은 각각의 가상 메모리를 할당받고, 각자의 독립성을 보장받기 때문에 다른 프로그램의 영역에 침범할 수 없다. 또한 유저 모드에서 실행되기 때문에 커널 공간에도 침범할 수 없다.


 하지만 커널 모드에서 실행되는 응용 프로그램은 모든 메모리를 자유롭게 사용할 수 있다.


 유저 모드에서 실행되는 어플리케이션이 높은 레벨의 권한을 필요로 하는 작업을 해야 하는 경우에는 System Service Call을 이용하는데, 유저 모드에서 실행되는 Thread가 커널 모드에 접근할 수 있는 권한을 받고, 시스템 자원을 이용한 뒤 다시 유저 모드로 돌아오는 것이다. 이는 syscall이라고 하는 instruction을 이용해서 실행이 가능하다.

블로그 이미지

__미니__

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

,

 모놀리식 커널(Monolithic Kernel)은 OS 구조의 한 형태이다. 대부분의 OS는 중심적인 기능을 수행하는 핵심 부분과 기타 주변 부분을 수행하는 부분으로 구성된다.


 OS의 핵심 부분 설계에는 가능한 핵심부를 작게 만드는 마이크로 커널과 주변 기능을 포함하여 만드는 모놀리식 커널이 존재한다. 리눅스는 모놀리식 커널을 채용하였으며, Windows NT는 마이크로 커널을 사용한다.



 마이크로 커널은 커널의 기능을 최소화하고 꼭 필요한 기능만을 넣어 둔 것이다. 핵심 기능인 Process Communication, I/O Control 등은 커널에 포함되어 있지만 File System, Network 등은 포함되어 있지 않고, 따로 User Application 형태로 존재하며 동작하게 된다.



 그에 비해 모놀리식 커널은 커널 내부에 Process management, Interrupt Handling, File System 등의 기능이 포함되어 있다. User Application에서 OS 내부의 기능을 사용하기 위해서는 System Call을 이용해야 한다. 새로운 기능이 등장하거나 Bug-fix가 발생했을 때, 커널 전체를 재컴파일해야 하므로 시간이 오래 걸린다는 단점이 있다.

'Knowledge' 카테고리의 다른 글

Greedy Algorithm + 회의실 배정  (0) 2016.06.21
Kernel/User mode  (0) 2016.04.15
libcapstone-dev 설치 방법  (0) 2016.03.12
PE 파일과 Memory-Mapped File  (0) 2015.12.24
Wireshark로 인증서 추출하기  (0) 2015.11.02
블로그 이미지

__미니__

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

,