반응형

ApplicationXP(Vista) Style의 테마 적용하기

 

XP 이후의 OS에서는 공용 컨트롤들이 좀더 예쁘장한 모습으로 나타납니다.

[ Windows 2000이전 공용 컨트롤들의 모습]

 

[ Windows XP이후 공용 컨트롤들의 모습]

 

 

 

 

내가 만들 Application에도 좀더 세련된 모양의 공용 컨트롤을 사용하려면 아래와 같이 작업하시면 됩니다.

 

n  VC 6.0

1. 아래와 같은 메니페스트 파일을 작성합니다.

MyApp.exe.manifest

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

 

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

             <assemblyIdentity version="5.1.0.0"

             processorArchitecture="x86"

             type="win32"

             name="MyApp.exe"/>

 

             <description> MyApp Application</description>

             <dependency>

                           <dependentAssembly>

                                        <assemblyIdentity

                           type="win32"

                           name="Microsoft.Windows.Common-Controls"

                           version="6.0.0.0"

                           publicKeyToken="6595b64144ccf1df"

                           language="*"

                           processorArchitecture="x86"/>

                           </dependentAssembly>

             </dependency>

</assembly>

 

2. resource.h파일에 MANIFEST_RESOURCE_ID를 정의 합니다.

resource.h

#define MANIFEST_RESOURCE_ID 1

 

3. rc파일에 리소스를 추가합니다.

MyApp.rc

/////////////////////////////////////////////////////////////////////////////

//

// 24

//

 

MANIFEST_RESOURCE_ID 24 MOVEABLE PURE " MyApp.exe.manifest"

 

n  VC 2003 이상

ü  위에서 작성된 manifest파일을 [ 프로젝트> 속성 > 구성속성> 메니페스트 도구> 입력 및 출력>추가 메니페스트 파일 ] 항목에 추가한 후 빌드합니다.


ü  혹은 아래의 문구를 stdAfx.h등의 헤더 파일에 추가 한 후 빌드합니다.

( 이 부분은 MFC 프로젝트의 경우, stdafx.h에 자동으로 추가되는 구분이며, #ifdef _UNICODE 로 감싸져 있어, Unicode프로젝트에는 자동으로 적용되는 부분입니다. )

X86

#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")

X64

#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")

 

 

 

 

반응형
반응형

StackFrame구성 - Stack Overflow

 

CallStack에 대한 이해를 돕고자 간단한 Quiz로 포스팅을 시작하겠습니다.

아래 와 같은 코드가 있습니다.

void Dummy()

{

           printf("In Dummy Function()\n");

 

           exit(0);

}

 

void SomFunction()

{

           BYTE Buf[4];

 

           printf("In SomFunction()\n");

            

           return ;

}

 

int wmain(int argc, _TCHAR* argv[])

{

           printf("Before call SomFunction()\n");

 

           SomFunction();

          

           printf("After call SomFunction()\n");

          

           return 0;

}

 

asm 코드를 쓰지 않고 SomFunction()을 수정하여 아래와 같은 결과를 출력한 후, 프로그램이 종료되도록 수정할 수 있을까요?

 

. 감이 오지 않는 분들은 아래의 글을 먼저 읽고 오시기 바랍니다.

[디버깅을 위한 기초지식 #3] CallStack - 프로시저 호출에 따른 스택의 구성

 

이제 어느 정도 방향을 잡으셨나요?

 

아래와 같은 방법을 사용하면 위의 문제를 해결할 수 있을 것 같습니다.

1.     Return Address가 저장되어 있는 Stack상의 Address를 구한다.

A.     asm 코드를 사용하지 않으려면, 해당 주소를 구하기 위해 로컬변수 Buf address를 통해 구해야 할 것 같습니다.

2.     1에서 구한 Address Dummy() 함수의 Address Overwrite하게 되면, SomeFunction이 모든 처리를 마치고 리턴할 때 Dummy()가 실행되게 됩니다..

생각보다 복잡하지는 않군요.

 

그럼 한단계씩 따라가 보겠습니다.

1.     SomeFunction이 복귀할 ReturnAddress가 저장된 Stack상의 주소 구하기

A.     스택 구성에 대한 링크된 포스트의 그림에 따르면 첫번째 로컬 변수의 위치는 ebp-0x4이므로, szBuf의 주소+0x4(szBuf사이즈) ebp의 주소가 됩니다.

B.     Rerturn Address의 주소는 ebp+0x4이므로, [ Buf+0x4/*ebp*/+4/*ebp+4*/ ]로 계산이 되겠습니다.

void SomFunction()

{

           BYTE Buf[8];

           DWORD *pDw = (DWORD *)(Buf+0x8/*ebp*/+4/*ebp+4*/);

 

           *pDw = (DWORD)Dummy;

 

           printf("In SomFunction()\n");

            

           return ;

}


 

2. 그럼 이제 구해진 주소에 Dummy()함수의 주소를 write해주기만 하면 되겠군요

*pDw = (DWORD)Dummy;



혹시 위의 코드를 기반으로 혹은 코드를 작성해서 따라해 보신분…?

머야? 안돼잖아~ 하신분도 있으리라 생각됩니다.

 

저도 테스트를 하다 보니 CallStack내에서의 첫번째 로컬 변수의 주소가 항상 ebp – 0x4의 주소에 위치하지는 않더군요.

 

위의 테스트 코드는 아래의 환경하에서 정상 동작했습니다.

n  VC++ 2008, Release모드, optimize off

 

n  Optimize(최적화)옵션을 켜게 되면, SomFunction()함수의 코드가 wmain()함수 안에 삽입되어 버리거나, stack frame이 생략되는 등 실제 작성된 코드와는 많은 부분이 달라질 수 있습니다.
실제로 아래의 코드는 [ release mode: 최적화-속도 최대화 ]를 설정하여 컴파일한 코드로 SomFunction()의 코드가 wmain()함수 안쪽에 박혀(?)있습니다.


 

n  또한 링크된 포스트의 그림에서 설명한 대로라면 SomeFunction()안의 szBuf변수의 사이즈를 8로 잡을 경우, 첫 번째 로컬변수의 주소가 ebp-0x8로 할당될것으로 생각했으나, 실제로는  ebp-0xc위치로 할당되었습니다.(어떠한 다른 규칙이 있는 것인지 제가 잘못 이해한것인지? 답을 아시는 분은 좀 알려주세요~)


 

별 활용성은 없는 코드이 겠으나, 위의 내용을 완벽히 이해하시면 CallStack BackTrace라던지 함수 호출 흐름 분석에 꽤 도움이 되지 않을까 생각합니다.


반응형
반응형

[MFC] Templete에 설정된 각 클래스 접근(MDI)

 

[CWinApp]

CTestApp *pApp = (CTestApp *)AfxGetApp();

 

[CMainFrame]

CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();

 

[CChildFrame]

CChildFrame *pChild = (CChildFrame *)pFrame->GetActiveFrame();

 

[CDocument]

CTestDoc *pDoc = (CTestDoc *)pChild->GetActiveDocument();

 

[CView]

CTestView *pView = (CTestView *)pChild->GetActiveView();

 

 

반응형
반응형

[MFC] Templete에 설정된 각 클래스 접근(SDI)

 

[CWinApp]

CTestApp *pApp = (CTestApp *)AfxGetApp();

 

[CMainFrame]

CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();


[CView]

CTestView *pView = (CTestView *)pFrame->GetActiveView();

 

[CDocument]

CTestDoc *pDoc = (CTestDoc *)pFrame->GetActiveDocument();

 


반응형
반응형

Calling Convention

콜링컨벤션
스택을 이용하여 파라미터를 전달할 때 파라미터를 스택에 넣는 순서와 전달된 파라미터를 어느곳에서 해제할 것인지 등을 결정하는 방식

) __cdecl

C 또는 C++프로그램에서 파라미터 전달시 디폴트로 사용하는 방식으로 이 방식에 의한 파라미터 전달은 오른쪽에서 왼족 방향으로 이루어지게 되며 프로시저를 호출한 쪽에서 파라미터에 대한 해제를 책임진다.


main()

{

           Sum(1, 2);

}

 

 

int Sum( int a, int b )

{

           return a+b;

}

Main:

           push    2

           push    1

           call       sum

           add      esp, 8

 

Sum:

           push    ebp ( 이전 프로시저의 ebp값을 저장 )

           mov     ebp, esp( 이전 프로시저의 ebp값을, push한 시점의 esp를 현재 스택 프레임의 ebp로 설정)

           mov     eax, dword ptr[ebp+0x8]

           add      eax, dword ptr[ebp+0xc]

           pop      ebp

           ret

) __stdcall
Windows API의 프로시저에서 사용하는 방식으로 파라미터 전달은 __cdecl방식과 같이 오른쪽에서 왼쪽방향으로 스택에 저장하게 되지만 파라미터의 해제는 프로시저가 복귀되기 전에 이루어 진다.

main()

{

           Sum(1, 2);

}

 

int Sum( int a, int b )

{

           return a+b;

}

Main:

           push    2

           push    1

           call       sum

 

Sum:

           push    ebp

           mov     ebp, esp

           mov     eax, dword ptr[ebp+0x8]

           add      eax, dword ptr[ebp+0xc]

           pop      ebp

           ret       8

장점

- 함수의 독립성이 뛰어남. 즉 프로시저를 부르기 전에 스택에 파라미터를 쌓아놓고 그 프로시저를 부르기만 하면 그 함수가 리턴되어진 후에는 그 프로시저의 스택포인터(esp)가 이전 상태로 복원되어 있으므로, 복귀된 후에 호출한 프로시저에 대하여 더 이상 신경을 쓰지 않아도 된다.

- 스택을 해제하는 코드가 호출한 프로시저 안에 있으므로 만약 이 프로시저가 여러곳에서 호출된다 하더라도 스택을 해제하는 코드는 프로시저 내에 하나만 존재하므로, 결국 __cdecl 방식에 비해 코드의 크기가 줄어든다.

) __fastcall

__fastcall 방식에서는 처음 두개의 파라미터는 스택을 이용하지않고 ecx edx 레지스터를 사용하며 그 이상의 파라미터에 대해서만 오른쪽에서 왼쪽 방향으로 스택에 저장하게 된다. 이 방식에서의 스택 제거는 __stdcall과 동일하다

) 정리

Calling Convention

파라미터 전달

스택메모리 제거

__cdecl

오른쪽에서 왼쪽 방향으로 스택에 저장

호출한 쪽에서 처리

__stdcall

오른쪽에서 왼쪽 방향으로 스택에 저장

호출 당한 쪽에서 처리

__fastcall

처음 두개의 파라미터는 ecx edx 레지스터에 저장, 그 이상의 파라미터는 오른쪽에서 왼쪽 방향으로 스택에 저장

호출 당한 쪽에서 처리

 

 

 

반응형
반응형


이 그림을 이해하는 것만으로도 (물론 대부분의 경우 디버거가 해주겠지만) 디버거의 도움을 받지 않더라도 함수 호출관계, 파라미터, 변수 등에 대한 많은 부가 정보를 읽을 수 있습니다.

프로그램 경력이 미천할 때( 지금도 마찬가지 입니다만…) 드라이버 개발자 분께서 어셈코드를 보고, 파라미터가 몇 개인 함수고,,, 인자가 어쩌고~ 하시면서 분석하는 과정을 경이롭게 지켜보았던 적이 있었는데… calling convention stack frame의 구성에 대한 이해가 수반된다면 얼추 흉내는 낼 수 있을거 같습니다. .

 
2011/07/25 - [디버깅] - Stack Frame구성 - Stack Overflow

2011/07/18 - [디버깅] - [디버깅을 위한 기초지식 #4] Calling Convention

반응형

+ Recent posts