2014년 8월 21일 목요일

boost build summary

Build and Install boost

  1. download boost library at http://www.boost.org/
  2. extract library to d:\work.lib\boost_1_56_0\
  3. build build tool
     d:\work.lib\boost_1_56_0>bootstrap.bat
     Building Boost.Build engine
    
     Bootstrapping is done. To build, run:
    
         .\b2
    
     To adjust configuration, edit 'project-config.jam'.
     Further information:
    
         - Command line help:
         .\b2 --help
    
         - Getting started guide:
         http://boost.org/more/getting_started/windows.html
    
         - Boost.Build documentation:
         http://www.boost.org/boost-build2/doc/html/index.html
    
     d:\work.lib\boost_1_56_0>
    
  4. build and install boost library at c:\Boost_x86\, c:\Boost_x64\
     d:\work.lib\boost_1_56_0>b2.exe toolset=msvc-10.0 --build-type=complete --build-dir=d:\work.lib\boost_1_56_0\build_dir_x86 --prefix=c:\Boost_x86 install
    
     d:\work.lib\boost_1_56_0>b2.exe toolset=msvc-10.0 address-model=64 --build-type=complete --build-dir=d:\work.lib\boost_1_56_0\build_dir_x64 --prefix=c:\Boost_x64 install
    
  5. If you want boost::python, install python before build boost. :-)

2014년 5월 21일 수요일

hypervisor 구현 세미나 자료

hypervisor 구현 관련 세미나 자료입니다.
vmware 같은 가상머신을 어떻게 만드는지에 대한 내용입니다.

재 작년인가에 세미나할때 만든 거 같은데 :-)
동영상도 있습니다. 음하하하


[slide share]

2014년 2월 4일 화요일

WinDbg :: dg 명령어

오랜만에 분석 할 꺼리가 생겨서 커널코드를 뒤적이다가, 세그먼트 관련 내용을 확인할 일이 생겼습니다.
하도 오랜만에 하는거라 그런지, dg 명령어까지는 생각이났는데, 출력 형태를 헤깔리는 바람에 쓸데없는 삽질을 하게되어 흔적이라도 남겨볼까하고요.

세그먼트 셀렉터는 상위 13비트를 GDT / LDT 인덱스로 사용합니다. 아래 처럼요.

; 15                                                2  1  0
; +----------------------------+-------------------+--+--+--+
; |                          index                 |TI| RPL |
; +----------------------------+-------------------+--+--+--+
;
; index
;   GDT 의 인덱스 값 ( GDT = index * sizeof(GDT Descriptor) )
;
; TI (Table Indicator)
;   0 이면 GDT (Global Descriptor Table)
;   1 이면 LDT (Local Descriptor Table)
;
; RPL (Requestor Privilege Level)

system context 에서 셀렉터와 세그먼트 디스크립터 출력내용입니다.

cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202

0: kd> dg 0 80
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0000 00000000`00000000 00000000`00000000 <reserved> 0 Nb By Np Nl 00000000
0008 00000000`00000000 00000000`00000000 <reserved> 0 Nb By Np Nl 00000000
0010 00000000`00000000 00000000`00000000 Code RE Ac 0 Nb By P  Lo 0000029b
0018 00000000`00000000 00000000`ffffffff Data RW Ac 0 Bg Pg P  Nl 00000c93
0020 00000000`00000000 00000000`ffffffff Code RE    3 Bg Pg P  Nl 00000cfa
0028 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3
0030 00000000`00000000 00000000`00000000 Code RE Ac 3 Nb By P  Lo 000002fb
0038 00000000`00000000 00000000`00000000 <reserved> 0 Nb By Np Nl 00000000
0040 00000000`00b96080 00000000`00000067 TSS32 Busy 0 Nb By P  Nl 0000008b
0048 00000000`0000ffff 00000000`0000f800 <reserved> 0 Nb By Np Nl 00000000
0050 ffffffff`fffe0000 00000000`00003c00 Data RW Ac 3 Bg By P  Nl 000004f3
0058 00000000`00000000 00000000`00000000 <reserved> 0 Nb By Np Nl 00000000
0060 00000000`00000000 00000000`ffffffff Code RE    0 Bg Pg P  Nl 00000c9a
0068 00000000`00000000 00000000`00000000 <reserved> 0 Nb By Np Nl 00000000
0070 00000000`00000000 00000000`00000000 <reserved> 0 Nb By Np Nl 00000000
0078 00000000`00000000 00000000`00000000 <reserved> 0 Nb By Np Nl 00000000
0080 Unable to get descriptor

WinDbg 의 dg 명령어 출력의 Sel 부분은 셀렉터의 RPL 필드를 00 으로 간주한 상태로 셀렉터 값을 출력합니다. 이걸 깜빡하는 바람에...@,.@

따라서 fs 셀렉터 0x53 -> 0x50 으로 치환해서 dg 출력에서 찾아야 합니다.
위에서는 0xffffffff`fffa0000 를 베이스로 하고, 리미트가 0x00003c00 인 GDT 엔트리를 가지는 것을 확인 할 수 있습니다. 다시 말해서 fs:[0] -> 0xffffffff`fffa0000 라는 거죠.

cs = 0x0010 : 00010 0 00 -> r0, gdt, Sel = 0010 0 00 -> 0x10
ss = 0x0018 : 00011 0 00 -> r0, gdt, Sel = 0011 0 00 -> 0x18
fs = 0x0053 : 01010 0 11 -> r3, gdt, Sel = 1010 0 00 -> 0x50
ds,es,gs
   = 0x002b : 00101 0 11 -> r3, gdt, Sel = 0101 0 00 -> 0x28

64 비트는 분석경험이 거의 없다보니, 새롭기도 하고, 어렵기도 하고...
언젠가 64비트 악성코드가 나오기 시작하면 분석가 생활을 접겠다고 하셨던 고XX 책임님이 생각납니다. :-)

2014년 1월 28일 화요일

const 위치와 의미

자주 사용하지만, 항상 뭔가 헤깔리는 그런것들이 있는데, const 도 그런 것들 중에 하나입니다. (저만 그럴지도...)
위치에 따른 const 의미를 정리해 보았습니다.

/**
 * @brief 
**/
class ConstPositionTest
{
public: 
    //> (const char*) msg : char* 가 const, 즉 msg 가 가리키는 데이터 변경 불가
    char* Function1(const char* msg)  
    {
        msg[0] = 't'; // error
        return m_msg;
    }

    //> char* (const msg) : msg 변수가 const, 즉 msg 포인터 변수 변경 불가
    char* Function2(char* const msg)  
    {    
        msg = m_msg; //error
        return m_msg;
    }

    //> 메소드 상수화, 이 메소드는 클래스 멤버를 읽을 수는 있으나 변경 할 수는 없음
    char* Function3(char* msg) const 
    {
        m_msg = msg; //error
        return m_msg;  
    }

    //> (const char*) : 리턴 값이 const char* 이므로 리턴 받는 변수도 const char* 이어야 함
    //> 따라서 리턴되는 포인터가 가리키는 데이터 변경 불가
    const char* Function4(char* msg)  
    {
        m_msg = msg;
        return m_msg; //반환 받는 타입이 const가 아닐 경우 error
    }
private:
    char* m_msg;
};

/**
 * @brief 
 * @param 
 * @see  
 * @remarks 
 * @code  
 * @endcode 
 * @return 
**/
bool test_const_position()
{
    ConstPositionTest test;
    char msg[] = "hello, const!";
 
    test.Function1(msg);
    test.Function2(msg);
    test.Function3(msg);

    const char* pMessage = test.Function4(msg);
    pMessage[0] = 0; // error
}

2013년 12월 16일 월요일

windows xp 에서 MSEC extension 사용하기


즐거운 연말을 보내기 위해 1주일 짜리 '소프트웨어 버그헌팅' 교육을 가게 되었습니다. 오호호~~
워드 프로세서 프로그램의 크래시를 일으키는 실습을 하던중에 예전에 '오 이런것도 있네' 했던 MSEC 확장이 생각났습니다. 

http://msecdbg.codeplex.com/

msec 은 MS 에서 배포하는 고마운 WinDbg 확장모듈로, 자동으로 크래시에 대한 분석을 수행하고, 이 크래시가 exploitable 한지 확인을 해줍니다. 
냉큼 다운로드 받고, WinDbg 로 로딩하려는데 계속 에러가 나는군요.


우선 depends 로 봤더니 msvcr11.dll, msvcp11.dll 이 필요하네요. visual studio 2012 로 빌드를 했나봅니다. visual studio 2012 redistributable package 를 설치해 주면 되겠죠?
(http://www.microsoft.com/en-us/download/details.aspx?id=30679)
재배포 패키지 설치 후 다시 로드를 해봐도 마찬가지로 에러를 내면서 로딩이 안됩니다. Orz



depends 로 다시 확인해 보니, Kenel32.dll 의 GetTickCount64 함수를 import 하고 있는데, msdn 에서 확인해보니 이 함수는 vista 부터 사용가능한 함수입니다. 
제 테스트 환경은 windows xp sp3 라서 dll 로딩이 실패할 수 밖에요.
어떻게 할까 한 10초 고민하다가 그냥 PE 의 import 테이블을 직접 고치는게 제일 편할것 같습니다. GetTickCount() 나 GetTickCount64() 나 뭐 정밀도의 차이가 좀 있을뿐 프로그램 돌아가는데는 별 문제 없으니, GetTickCount() 함수를 import 하도록 실행파일을 변경시켜 버리면 될것 같습니다.


100만년 전에 열심히 사용하던 LordPE 를 검색해서 다운로드 받고 실행합니다. (우와 PE+ 도 지원하고, 정말 오랜만이네요, 반갑다!)



IAT 를 고쳐야 하니까 'Directories' 버튼을 눌러주고요.





GetTickCount64 를 GetTickCount 로 변경해주면 됩니다.

이제 다시 !load winext/msec.dll 명령으로 extension 을 로드하고, !exploitable 명령을 실행해보면... 
오오옷! exploit 가능한 크래시군용~ 



 참 쉽죠? :-) (쉽긴 개뿔...-_-;;)




2013년 11월 11일 월요일

Visual studio 컴파일러 버전 별 처리하기

최근 Visual Studio 6 으로 개발을 하고 있는데, 여간 귀찮은게 아니네요. ㅠ.ㅠ

std::list 를 사용하려고 했더니 엄청나게 많은  warning 을 뱉어내기에 봤더니 


C:\Program Files (x86)\Microsoft Visual Studio\VC98\INCLUDE\list(131) : warning C4786: 'std::reverse_bidirectional_iteratorstringunsigned short>,std::allocator >,std::allocator
td::basic_stringunsigned short>,std::allocator > > >::const_iterator,std::basic_stringunsigned short>,std::allocator >,std::basic_string ,std::char_traits,std::allocator > const &,std::basic_stringunsigned short>,std::allocator > const *,int>' : identifier was truncated to '255' characters in the debug information

이런 경고네요. VS6 은 찾아보기 파일이나 디버그 정보에 255 자를 넘는 문자열을 처리못하나 봅니다. 
이런건 뭐 별수 없죠. 워닝을 끄는 수 밖에요. 


아래 코드를 무식하게 stdafx.h 에 넣어두었습니다. 




#if defined(_MSC_VER) && _MSC_VER < 1300
#pragma warning (disable: 4786)
#endif

참고로 _MSC_VER 매크로 값은 아래와 같다고 합니다.





1000 : Visual C++ 4.x (4.0)
1100 : Visual C++ 5    (5.0)
1200 : Visual C++ 6    (6.0)
1300 : Visual C++ .NET (7.0)
1310 : Visual C++ .NET 2003 (7.1)
1400 : Visual C++ .NET 2005 (8.0)
1500 : Visual C++ .NET 2008 (9.0)
1600 : Visual C++ 2010 (10.0)
1700 : Visual C++ 2012 (11.0)


끝!!

2013년 9월 11일 수요일

커널모드 유닛테스팅 프레임웤 활용하기

간단하게 커널모드 코드를 테스트 할 수 있는 방법에 대해서 설명할까 합니다.

응용프로그램 레벨에서는 사용할 수 없는 인스트럭션 (예. mov eax, cr0 )들에 대한 테스트가 필요한 경우도 있고, 간단한 커널모드 코드 조각을 테스트해야 하는 경우도 있고, 커널모드 안티디버깅 같은거 테스트 할 때... 필요한 상황이야 많습니다.

대부분의 응용프로그램 개발자들은 커널모드 프로그램 개발에 대해서 알지 못하고, 간단한 테스트 하나 하자고, 두꺼운 책들과 씨름하기엔 너무 귀찮고, 좀 어렵죠?

좀 쉽게 할 수 있는 방법이 없을까요? (있으니까 이런 글을 쓰고 있겠죠.)
유닛테스트 프레임웤 중에 cfix 라는 녀석은 윈도우즈 커널모드 코드에 대한 유닛테스팅을 지원합니다. 예전에도 몇번인가 제 블로그에서 다뤘던거 같은데요.

cfix 를 이용해서 테스트할 커널 코드를 작성하고, 프레임웤을 이용해서 실행해보면 되는거죠.  드라이버를 실행하기 위한 서비스 등록/시작/중지/제거기능, 드라이버 구현을 위한 기본 코드따위는 프레임웤이 알아서 다 해줍니다.

우린 그냥 프레임웤에 테스트할 코드만 넣어주면 땡입니다. 아싸~

우선 여기에서 cfix 프레임웤을 받아서 설치합니다.
홈페이지에 보면 Visual Assert 와 cfix 두 가지가 있는데 읽어보시면 알겠지만 visual assert 는 cfix 를 기반으로 만들어진 visual studio 용 플러그인입니다.

둘다 사용법은 같으니 아무거나 설치해도 됩니다만 나중에 visual studio 에서 유닛테스트를 사용할 때도 쓰려면 visual assert 를, 드라이버 테스트만을 위한거라면 cfix 를 설치하시면 됩니다.

설치할때 주의할 점은 설치 경로에 공백문자나 한글이 있는 경우 커널모드 유닛테스트를 사용할때 문제가 발생 할 수 있습니다. 그냥 C:\VisualAssert 에 설치하는게 가장 좋습니다.


C:\VisualAssert 아래 Doc, example 에 보면 필요한 내용은 다 있습니다. 그거 참고해서 알아서들 하세요... 라고 하고 싶... :-)

C:\VisualAssert\examples\KernelMode 에 보면 우리에게 필요한 모든게 다 있습니다.



suite.c 파일에 있는 주석들 대충 읽어보면 뭐가 뭔지 알거에요. 나중에 읽어보시고, 아래처럼 간단하게 고쳐봅시다.

#include 

static void __stdcall Test1()
{
    // CR4 레지스터에 접근해 볼까요?
    unsigned long _cr4=0x00000000;
    __asm 
    {
        mov eax, cr4
        mov _cr4, eax
    }
    
    CFIX_LOG(L"cr4 = 0x%08x", _cr4);
}

CFIX_BEGIN_FIXTURE( MyFixture )
 CFIX_FIXTURE_ENTRY( Test1 )
CFIX_END_FIXTURE()

이제 드라이버 코드를 빌드해야 겠죠? 당연히 드라이버 빌드를 위해서는 DDK가 설치되어있어야 합니다. 우선 32 비트 xp 에서 테스트 할 것이므로 아래 그림처럼 WindowsXP \ x86 checked Build Environment 를 선택합니다.
당연히 디버깅을 할 상황도 생길 수 있기때문에 checked build 를 선택하는게 좋겠죠?



MakeFile, Sources 파일이 위치한 경로로 이동해서 "build -ceZ" 명령을 내려주면 됩니다.

빨간 부분으로 표시한 곳을 보면 에러가 발생했네요.
잘 읽어보면 에러를 워닝으로 간주하도록 설정이 되어있어서 워닝 -> 에러가 된 상황이죠. ( 간혹 워닝은 워닝이니까 하고, 무시하는 님들이 계신데, 워닝은 에러... 라고 생각하고, 미주알 고주알 따져서 반드시 다 없애주는 버릇을 들여줘야 합니다. 무시한 워닝 하나로 인해 정말 찾기 힘든 버그 만들어서 개고생 하는 사람들 많이 봤습니다 )

워닝 메세지를 보니 cr4 라는 레이블을 인식못한다는 군요. 이것은 DDK 에 내장된 어셈블러가 'cr4' 문자열을 레지스터 이름으로 인식하지 못하고, 일반 문자열로 인식하기 때문이겠죠.

mov eax, cr4 명령을 기계어로 넣어주거나, __readcr4( ) 함수를 이용하면 됩니다. 자세한건 인터넷 찾아보시고요. 아래 처럼 코드를 수정해 주시고, 다시 build -ceZ 명령을 해봅시다.

static void __stdcall Test1()
{
    // CR4 레지스터에 접근해 볼까요?
    unsigned long _cr4=0x00000000;
    __asm
    {
        _emit 0x0f   ; mov eax, cr4
        _emit 0x20 
        _emit 0xe0   
        
        mov _cr4, eax
    } 
    
    CFIX_LOG(L"cr4 = 0x%08x", _cr4);
}


아 ㅅㅂ 또 에러인데, 이번도 warning 때문에 발생한 문제네요. 그런데 워닝 메세지도 없습니다. ㅠ.ㅠ

build 명령을 내리면 현재 MakeFile 이 있는 디렉토리에 buildXXX_XXX_XXX.wrn/err/log 파일이 생성되는데 각 파일들은 워님, 에러, 로그를 담고있습니다.
wrn 파일을 열어보면 아래와 같은 내용이...

1>c:\visualassert\examples\kernelmode\cl : warning D9035 : option 'Wp64' has been deprecated and will be removed in a future release
1>c:\visualassert\examples\kernelmode\suite.c : warning C4819: The file contains a character that cannot be represented in the current code page (949). Save the file in Unicode format to prevent data loss

대충 요약해 보면 첫 번째 라인은 64 비트 호환모드 옵션(/Wp64)때문인데 아마 vs 2003 이후 컴파일러부터는 필요없는 옵션일겁니다.
두 번째는 소스 파일 인코딩이 cp949 가 아니라는 거죠. 외국에서 만든거니 코드페이지가 달라서 발생한 문제입니다.

다 귀찮으니 SOURCES 파일의 컴파일 옵션을 아래처럼 수정하고, 다시 빌드합니다.
( 64 비트 호환모드 체크 안함 / 워닝을 에러로 처리 안함 )

# MSC_WARNING_LEVEL=/W4 /WX /Wp64
MSC_WARNING_LEVEL=/W4


그대로 따라했다면 " C:\VisualAssert\examples\bin\chk\i386\kern.sys/pdb/obj/lib " 같은 파일들이 생겼을겁니다. 젠장, 이제 겨우 빌드에 성공했군요. -_-;

이제 빌드 한 커널드라이버를 실행하기 위해서 가상머신에 cfix 프레임웤을 설치해야 합니다. 사실 개발 머신에는 cfix 프레임웤을 설치할 필요는 없으나 예제 코드를 그대로 사용하려고 했던거고요.

정말 중요한건 드라이버를 실행할 PC 에 cifx 프레임웤을 설치해야 하는거죠.
가상머신에 visual studio 가 설치되어있지 않은 경우 visual assert 를 설치하려하면 오류가 나고, 설치가 중단됩니다. 당연히 visual assert 는 visual studio 플러그인이니까요. 홈페이지에서 cfix 를 다운로드 해서 설치하거나 " c:\VisualAssert\bin\i386 " 폴더 아래의 파일들을 가상머신의 적당한 경로에 복사합니다. 편한대로 하세요~

저는 가상머신의 c:\dbg 폴더 아래에 복사했고, 빌드 할 실행파일 kern.sys 도 같은 경로에 복사했습니다. c:\dbg\cfix32.exe -kern kern.sys 명령을 실행하면 아래처럼 우리가 작성했던 코드의 결과를 확인할 수 있습니다.


참~ 쉽죠~?! ^__^