1. 가상메모리 기본( VirtualAlloc )

more..


2. MMF 기본

more..


3. MMF 를 이용한 그리기 통신( B가 A에게 오버헤드를 발생시킨다.ㅜ_ㅜ )

more..


4. DLL Inject

more..


Tag | ,
1. 메모리

  - 16비트
    1) jmp A : 3 은 결국 3번지로 이동하라는 명령이다. 이는 CS : 3 ( CS레지스터리부터 3번지로 개선됐다. )
    2) 16bit 시절부터 offset을 이용하여 주소를 결정하였다.
code Segment : CS
data  Segment : DS
stack Segment : SS
TEB Segment : FS

mov [10], 100 : DS로부터 10떨어진곳에 100을 넣어라
mov [500], 100 : DS로부터 500떨어진곳에 100을 넣다가 다른 메모리에 접근할 수도 있다. 보안문제 발생

  - 32비트
    1) 재배치를 해준다. GDT( Global Descripter Table ) 을 거쳐야 가상주소가 논리주소,선형주소가 된다.
Index Address Size Access
1 1000 5000 R
2 7000 3000 R/W

    2) mov [100], 100  : DS가 Index 2라면 7000에서 100떨어진곳에 100을 추가한다.
    3) mov[6000], 100 : 하지만 잘못된접근이나 권한밖의 일은 리셋시켜서 보호해준다. Table의 역할!!!
    4) Windows 나 Linux는 GDT 를 쓰지 않고 Intel CPU와의 호환을 위해 그냥 만들어 놓기만 한다.
    5) 그러므로 결국 가상주소가 논리주소,선형주소가 된다.

  - 가상주소 + 세그먼트 => GDT => 선형주소(linear Address ) // Segmentation 이라 한다.

2. 페이징

  - GDT 테이블을 거친 선형주소는 4G가의 메모리를 참조 할 수 있다.(가상주소랑 일치)

  - Page Table
    1) PFN (Page Frame Number) : 메모리 관리를 효율적으로 하기 위하여 물리 메모리를 4k로 잘라서 보관!
    2) 물리메모리가 1MB 라면 이를 잘게 나눠서 0~255 번의  PFN 를 매기는 것이다!!
    3) 하지만 물리메모리가 4G 라면 너무 많은 PFN이 생성되므로 2단 주소로 바꿔서 관리를 해준다.

사용자 삽입 이미지

    4) 선형주소 => PageDirectory => PageTable => PageFrame => Offset  의 순서 물리메모리의 주소를 찾아간다. 이 모든것이 선형주소에 담겨 있는것을 볼 수 있다.
    5) 선형주소는 CR3 레지스터를 참고하여 페이지디렉토리를 찾아간다.

  - 이 모든 작업은 Intel CPU가 알아서 해준다. 그저 테이블과 CR3에 주소만 담아 놓으면 된다.
  - PFN 에는 32bit의 주소만 갖고 있는것이 아니라 48bit로 구성되어 16bit는 HDD에 백업되어 있는 물리메모리 값을 파악해서 다시 물리메모리에 올려 놓는 작업도 하고 있다.

3. 공유 메모리

  - A.exe 에 전역으로 선언된 변수가 있다면 이를 2번 실행시 데이터와 코드를 공유하여 물리메모리에 올린다.
  - 하지만 전역 변수에 데이터를 쓰게 되면 Copy On Write 를 하여 새로운 메모리 공간을 만들어 준다.
  - 즉, 처음에는 메모리 영역을 공유하지만 쓸때에는 복사본을 만들어서 딴 공간을 만들게 된다.

  - Copy On Write 를 하지 않는다면 전역변수를 서로 공유할 수 있게 되는 것이다.
// 일반 전역 변수..  .data section에 놓인다. 기본적으로 COW하는 속성을 가지고 있다.
int x = 0;

// exe에 새로운 data 섹션을 만든다.
#pragma data_seg("AAA")
int y = 0;      // 공유 섹션으로 만드려면 반드시 초기값이 필요하다.
#pragma data_seg()

// 특정 섹션의 속성을 지정한다. - Read, Write, Share( COW 속성이 제거된다. )
#pragma comment( linker, "/section:AAA,RWS")    // Copy On Write
- .exe 에 Share 속성을 가진 AAA 섹션이 생긴것을 알 수 있다.
- 전역변수는 .data 에 있지만 AAA라는 Section을 만들어서 물리메모리 상에서 같이 사용하는 것이다.
- 같은 프로세스 끼리는 공유가 필요 없으므로 DLL에 써서 다른 프로그램에도 읽게 해준다면 더 효율적..
- A.exe => int x;(전역), x.dll에 선언 <= B.exe
// SHARE.dll - COW를 하지않는 DLL상에서의 전역 변수 만들기
// 공유 메모리는 반드시 초기화 해야 한다.,!!!!!!!!!!!!!!

#pragma data_seg("SHARED")
char buf[1024] = { 0 };
#pragma data_seg()
#pragma comment( linker, "/section:SHARED,RWS" )
/////////////////////////////////////////////////////
extern "C" __declspec(dllexport) void SetData(char* s)
{
    strcpy( buf, s );
}
extern "C" __declspec(dllexport) void GetData(char* s)
{
    strcpy( s, buf );
}
/////////////////////////////////////////////////////
// A.cpp - DLL에서 가져와서 사용하기!!!

    HMODULE hDll = LoadLibrary( "SHARED.dll" );
    F SetData = (F)GetProcAddress( hDll, "SetData" );
    F GetData = (F)GetProcAddress( hDll, "GetData" );

Tag | ,

10.12(금) 이론-1( TLS, 우선순위 )

from Study/System 2007/10/14 20:46 view 22879
1. TLS

  - Thread Local Storage ( 스레드별로 따로 할당되는 공간 )
  - 스레드별로 독립적인 공간을 만들어 준다.
  - 정적 TLS 를 만들기 위해선 __declspec(thread) 를 static 변수 또는 전역변수 앞에 붙여준다.
  - 주스레드에서 새로운 스레드를 생성하면 새로운 TLS 공간이 생기고 주스레드의 TLS의 내용과 dll의 TLS의 내용을 가져온다. ( .tls 라는 섹션이 생긴다!!! )

  - 하지만 LoadLibrary 를 사용하여 새로운 dll을 가져올 때 TLS의 초기화는 이미 끝나 있다.(명시적 로드시)
  -  정적 TLS의 문제점 : DLL에 만들고.. 해당 DLL을 LoadLibrary로 사용하면 TLS에 있는 변수가 제대로 동작하지 않는다. => 동적 TLS를 사용하자.

  - 동적 TLS : TlsAlloc, TlsFree, TlsSetValue, TlsGetValue
  - 항상 똑같은 Slot을 같은 용도로 사용한다.
  - 동적 TLS는 프로세스에서 관리 하게 되는데 사용하면 1 비사용은 0으로 관리를 하게 된다.
  - 전역변수( 모든 스레드 공유 )로 TLS Index를 보관해야 한다.

2. _beginthreadex
// 임의의 함수가 내부적으로 지역변수만 사용하고 있다. - 멀티스레드에 안전
// 임의의 함수가 내부적으로 static 지역변수를 사용하고 있다. - 멀티스레드에 불안전

unsigned int __stdcall _beginthreadex( ... )
{
    // C함수들 중에서 내부적으로 static 지역변수를 사용하는 함수를 위해서
    // 힙에 메모리를 할당한다.
    _tiddata* p = malloc( sizeof(_tiddata) );

    p->func = 사용자 함수;

    // TLS에 방금 할당한 P를 보관한다.
    HANDLE h = CreateThread( 0, 0, threadstartex, p, 0, 0 );
}

void threadstartex( _tiddata* p )
{
    p->func();
    free( p );  // 메모리 제거
}

  - strtok는 내부적으로 static 지역변수를 사용하므로 멀티스레드에 불안전 하다. VC6.0( LIBC.lib )
  - 그래서 VC2005 부터는 LIBCMT.lib 를 사용하여 멀티스레드에 Thread Safe 를 제공한다.(TLS사용)
 
  - 멀티스레드를 사용하고자 할때는 _beginthreadex를 사용하여 TLS에 구조체 하나를 생성해줘야 한다.. 그래야 strtok와 같은 함수를 안전하게 사용할 수 있다.
  - static이 스레드 하나에 종속되어 다른 스레드에 영향을 끼지치 않는다는 것을 보장!!


1. 우선순위

  - 스레드는 프로세스 우선순위에(8)에 상대적으로 매길 수 있다.
  - 8 을 기준으로 -1, +1 을 한다. SetPriorityClass, SetThreadPriority ( 우선순위 변경 )

  - RTOS 는 반드시 우선순위를 지켜야 한다.( 우선순위 역전 현상을 방지 )
사용자 삽입 이미지

  - 위 그림은 2 ~ 3 ~ 1 순으로 끝나게 된다. 3이 뮤텍스를 획득하고 파서 대기하는라고 2가 계속 실행되는 현상이 발생하는 것이다.
  - 만약에 인공위성이 지구와 통신 하는 것이 3이라면 영원히 실행되지 않을 수 있다.

  - 이를 방지하기 위해서 3이 뮤텍스 대기 상태에 빠지면 뮤텍스를 획득한 스레드를 자신과 같은 우선순위로 만들어 뮤텍스를 반납하게 만들어 줘야 한다. 위 그림에서 1을 우선순위 3으로 만들고 반납하게 해주면 된다.

1. 스레드 친화력 : 어떤 스레드를 어떤 CPU에서 실행할 것인가를 정할 수 있을까??(듀얼)
 
  - SetThreadAffinityMask http://www.microsoft.com/korea/msdn/library/ko-kr/dev/vc/optimization.aspx

2. 스레드, 프로세스가 지니고 있는것

  - 스레드 : Stack, MessageQ, TLS, HOOK
  - MessageQ는 스레드당 1나씩 존재하는데 +0x040 Win32ThreadInfo  : Ptr32 Void 유저모드에서 관리!!.
Tag | ,
1. 정적 TLS

more..


2. 동적 TLS

more..


3. 알고리즘 시간을 측정

more..


4. 스레드에 메시지 루프 집어넣기

more..


5. 스레드에서 주 스레드로 메시지 보내기

more..


6. 공유메모리

more..


7. 공유메모리의 DLL화

more..



Tag | ,
1. 스레드풀

  - 최초에 Thread를 10개를 만든 후에 일이 필요하면 자고 있는 스레드를 깨워서 일을 시킨 후에 다시 재운다.
  - 15개의 일이 들어오면 나머지 5개는 Q에 대기 시켜 놓고 일을 다하면 실행시켜 준다.
  - 미리 만들어 놓고 내가 쓰레드를 관리한다는 개념이 쓰레드 풀링이다~~!

  - 핵심은 세마포어를 활용하는 것!! 대기상태를 세마포어로 구현하여 활용하면 된다.!!!
  - 세마포어는 리소스 카운팅에 적합하다.!!

2007/10/14 - [Study/System] - 10.11(목) 실습-1
Tag | ,
1. 뮤텍스

  - 화장실 열쇠가 한개만 존재하여 한사람씩 사용가능한 경우..
  - Enter ~ Leave Critical 은 전역변수로 단일 프로세스에서만 사용하나 뮤텍스는 다중프로세스에서 사용.
  - KMUTANT로 구조체를 확인 가능하다.
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListEntry  : _LIST_ENTRY
   +0x018 OwnerThread      : Ptr32 _KTHREAD
   +0x01c Abandoned        : UChar
   +0x01d ApcDisable       : UChar

  - CreateMutex( 0, FASLE, "m" ); // 또한번 CreateMutex("m")를 하면 Open으로 여는 것과 같다.
  - 처음 소유자 스레드 ID는 0이지만 10번 스레드를 얻게 된다면 Id엔 10을 채우고 재귀횟수가 1이 된다.
  - ReleaseMutex를 하지 않고 스레드가 끝나면 WAIT_ABANDONED 포기된 mutex가 발생한다.

2. 세마포어

  - 정해진 자원을 카운트 한다.
  - CreateSemaphore( 0, 3, 3, "s" ); // 보안:0, signal:+3, 이름:"s", 참조:0, limit:3
  - WaitForSingleObject 를 하게 되면 signal은 1씩 줄어들게 되고 0 이 되게 되면 나중에 실행되는 스레드는 signal 이 1이 될때까지 대기 해야한다.

  - Limit가 1인 세마포어는 뮤텍스와 비슷하나 차이점이 있다.
    1) 뮤텍스는 소유권이 있지만 세마포어는 소유권이 없다.
    2) 즉, 열쇠를 공동으로 관리 한다는 말이다. 뮤텍스는 자기가 꼭 관리 해주지만 세마포어는 자원의 갯수를 감소시키고 증가시키는 작업을 다른 스레드(사람)가 해줘도 된다. 열쇠를 모두 공유한다는 개념으로 이해..
    3) 모두 공유한다는 개념이 있으므로 꼭 접근을 동기화 해줘야 한다.!!!!

3. 이벤트

  - Event : 스레드간 통신에 활용된다.
HANDLE h = CreateEvent(
        0,      //보안
        FALSE// Reset의 종류( T:manual, F:auto )
        FALSE// 초기 signal 상태 ( T:signal, F:non-signal )
        "e" );  // 이름
 
  - 2번째 인자를 FALSE로 하여 AutoReset 으로 하면 WaitForSingleObject 통과시 자동으로 리셋된다.
    1) 여러개의 스레드에 이벤트"e"가 존재하면 누가 먼저 깨어날지는 알수가 없게 된다. "경쟁 상태"

  - 2번째 인자를 TRUE로 한다면 manual 상태가 되어  WaitForSingleObject 통과시 signal 상태이다.
    1) 여러개의 스레드에 이벤트"e"가 존재한다면 모두에게 신호를 보내기도 한다.
    2) SetEvent 일때는 WaitForSingleObject 통과시 signal 상태이지만
    3) PulseEvent 일떄는 WaitForSingleObject 통과시 non-signal이 되어 한번씩만 꺠운다.!!
    4) CreateEvent를 동일한 이름으로 두번 수행하게 되면 두번째로 생성되는것은 Open의 의미를 갖는다.

2007/10/14 - [Study/System] - 10.11(목) 실습-1

Tag | ,
1. 뮤텍스

more..


2. 세마포어

more..


3. Event

more..


4. 생산자와 소비자

more..


5. STL list의 Thread Safe

more..


6. CriticalSection 단위전략 으로 사용해보기.

more..


7. 스레드 풀 ( 세마포어를 이용 )

more..


8. 프로세스 감시( 종료를 기달린다. )

more..


Tag | ,

10.9(화) 이론-2( 스레드 )

from Study/System 2007/10/14 15:58 view 19811
1. 스레드!!!

  - 개념 ( 윈도우는 스레드기반으로 돌아간다. )
    1) 가상주소 => 페이지테이블 => 물리주소
    2) CR3 : 페이지 테이블의 주소
    3) CPU는 10ms씩 인터럽트가 발생하여 Context Switching 이 발생
    4) 인터럽트 Handler 는 스케줄러 담당한다. 두개이상의 프로세스가 동시에 실행되도록 한다.
    5) 퀀텀Time : 20ms 최소의 실행시간을 보장해준다.
    6) 메시지Q는 GUI 요소를 갖는 윈도우만 가지고 있다.
    7) GetMessage() 에서 message가 없다면 Context Switching 이 발생..
    8) Sleep(0); 을 해서 강제로 C.W 발생..
    9) 메모리 관리 : 프로세스가 CR3를 가지고 있다.(ReadProcessMemory는 CR3의 주소값을 참조.)
   10) 실행흐름 : 스레드가 관리한다.

  - 함수
    1) CreateThread, CreateRemoteThread ( 다른프로세스에 스레드를 생성 ), _beginThreadex

  - 주스레드에서(main()) 스레드A를 생성하게 되면 ETHREAD에 1MB의 스택영역이 생성된다.
  - 주스레에서 main리턴하게 되면 프로세스가 종료되고, ExitThread를 해주면 주스레드만 종료된다.
  - 다른 스레드의 종료를 대기해줘야 할때 ( WaitForxxx )
    1) WaitForSingleObject - 스레드구조체의 staterk signal 상태가 되기를 기다리게 된다.

  - WaitForSingleObject 의 원리
    1) dt nt!_KEVENT, dt nt!_KTHREAD 에는 공통적으로 _DISPATCHER_HEADER 가 있다.
+0x000 Header           : _DISPATCHER_HEADER
///////////////////////////////////////////////////////////////////////////////////////
   +0x000 Type             : UChar
   +0x001 Absolute         : UChar
   +0x002 Size             : UChar
   +0x003 Inserted         : UChar
   +0x004 SignalState      : Int4B  <= 모든 KO는 이를 가지고 있다. 실행과 대기를 위해서~~
   +0x008 WaitListHead     : _LIST_ENTRY

2. MulitiThread
DWORD CALLBACK foo( void* p )
{
    int x;                // TLS 내에 생긴다.(Thread Local Storage) 지역변수는 Thread Safe 
    static int y;       // 프로세스의 static 공간에 생긴다. 스레드에 안전하지 않다. CriticalSection

    return 0;
}

- CriticalSection 영역을 ThreadSafe 하기 위해선 CRITICAL_SECTION을 사용한다.
- Serializetion( 직렬화 ) : 2차선 -> 1차선으로 바꿔서 스레드 한개만 활동하게 한다.

- 듀얼 코어에서는 자러가는시간 1000ms 과 깨어나는 시간 100ms 라면 깨어나는 Thread가 계속 실행될 수 있다. 그래서 SpinCounter 500ms 정도로 설정하여 CS에 진입을 재시도 하게 한다.

3. 원자 연산 ( Atomic Operation )
DWORD CALLBACK foo( void* p )
{
    for ( int i = 0; i < 10000; ++i )
    {
        // COM 기반 기술에서 자주 사용한다.!!!!!!!
 
      InterlockedExchange( &x, 0 ); // x = 0
        InterlockedExchangeAdd( &x, 5 );    // x = x+5;
        InterlockedDecrement( &x ); // x -= 1;
        InterlockedIncrement( &x );    // lock inc x 로 구현된 함수. x += 1

        x = x+1;    // 보장받지 못한다.

        __asm
        {
            lock inc x // inc 는 원자 연산이다. 즉, inc 실행중 절대 Context Switch가 발생안함.


           // 아래 명령어는 원자 연산을 보장 하지 못한다.

            mov eax,    x
            add eax,    1
            mov x,        eax
          ///////////////////////////////////////////////
        }
    }
    return 0;
}

  - asm으로 원잔연산을 보장 해주기 위해선 inc 라는 명령어를 사용한다.
  - 듀얼코어에서는 lock 이라는 접두어를 붙여줘야 한다.
  - InterlockIncrement : lock inc x 를 구현해 놓은 함수이다...


TIP : 함수의 어셈 코드 보기

HMODULE hdll = GetModuleHandle( " xxx.dll " );  // 함수가 포함된 dll
void* p = (void*) GetProcAddress( hdll, "함수명" );
printf( "%p\n", p );

=> 함수의 dll에서의 주소(p)를 디스어셈블리창에서 찾아보면 나온다..
Tag | ,

10.9(화) 이론-1

from Study/System 2007/10/14 14:55 view 18033
1. ReadProcessMemory

 - 프로세스간의 독립성은 보장되지만 디버깅을 위해 함수를 제공한다.
 - ReadProcessMemory, WriteProcessMemory

 - int 3( 브레이크 포인트 ), TF 레지스터 1 로 세팅하면 CPU가 한줄 단위로 읽게 된다.
 - 코드영역을 읽어와서 보여줄 수도 있다.( MinDbg, DebugActiveProcess ) 실행중인 프로세스와 연결!!
 - CreateProcess( option에 DEBUG_ONLY_PROCESS ) 를 준다.
 - WaitForDebugEvent 를 하면 DEBUG_EVENT에 정보가 들어가게 된다.

2. 컴파일 모드

  - Win32 Debug : 개발시, 실행오류체크와 관련된 메크로나 함수가 컴파일 대상에 포함된다.
  - Win32Release : 완성된 프로그램 일 경우 이 모드로 놓고 컴파일 해줌으로써 디버그 모드에서 수행되던 매크로나 함수는 컴파일 대상에서 제외되므로 보다 최적화된 코드가 탄생된다.

  - ASSERT 매크로
    1) Debug에서만 수헹, ASSET(조건식) 0 or 1
    2) 조건식이 거짓일 경우 ASSERT라는 이름의 Dialog박스를 출력하여 오류정보를 보여준다.

  - VERIFY 매크로
    1) Debug 모드에만 수행되며 ASSERT 와 동일한 매크로 이다.

  - TRACE 매크로
    1) Debug모드에서만 수행된다. 형식은 printf와 동일하며 Output 창에 출력된다.

  - OutputDebugString () == TRACE 괄호안의 문자열을 출력한다.

  - Dump()
    1) 디버그 모드에서만 수행한다.
    2) 특정개체에 저장된 데이타의 모든 항목을 Output 스크린상으로 전부 출력할 수 있는 코드를 추가가능.
Tag | ,

10.9(화) 실습-1

from Study/System 2007/10/14 14:36 view 66702
1. Debug 용 에러출력매크로( TRACE, ASSERT, VERIFY )

more..


2. CreateThread 와 종료대기

more..


3. 멀티 스레드와 동기화

more..


4. CrtiticalSection 의 Leave 보장..

more..


5. Atomic( 저수준 단계에서 원자연산 보장!! )

more..


6. ReadProcessMemory

more..


Tag | ,