1. 스택의 원리
2. 기본힙과 새로운 힙 만들기
3. 동적 TLS를 사용한 DLL ( strtok 문제 해결 )
4. DLL이 로드되는 과정 보기(위예제랑 연동)
5. Hook Dll 만들기
6. Hook 한 메시지 읽어오기( Friend)
more..
void print( MEMORY_BASIC_INFORMATION* p );
int main()
{
char* addr = (char*)0x0;
MEMORY_BASIC_INFORMATION mbi;
while( addr < (char*)0x80000000 )
{
// 가상 주소 공간의 상태를 조사한다.
VirtualQuery( addr, &mbi, sizeof(mbi) );
print( &mbi );
addr += mbi.RegionSize;
}
}
void print( MEMORY_BASIC_INFORMATION* p )
{
char* s = (char*)p->BaseAddress;
char* e = s + p->RegionSize - 1;
printf( "%08x ~ %08x : ", s, e );
char* state = "unknown";
switch ( p->State )
{
case MEM_FREE: state = "Free "; break;
case MEM_RESERVE: state = "Reserve"; break;
case MEM_COMMIT: state = "Commit"; break;
}
printf("%s\n", state );
}
int main()
{
char* addr = (char*)0x0;
MEMORY_BASIC_INFORMATION mbi;
while( addr < (char*)0x80000000 )
{
// 가상 주소 공간의 상태를 조사한다.
VirtualQuery( addr, &mbi, sizeof(mbi) );
print( &mbi );
addr += mbi.RegionSize;
}
}
void print( MEMORY_BASIC_INFORMATION* p )
{
char* s = (char*)p->BaseAddress;
char* e = s + p->RegionSize - 1;
printf( "%08x ~ %08x : ", s, e );
char* state = "unknown";
switch ( p->State )
{
case MEM_FREE: state = "Free "; break;
case MEM_RESERVE: state = "Reserve"; break;
case MEM_COMMIT: state = "Commit"; break;
}
printf("%s\n", state );
}
2. 기본힙과 새로운 힙 만들기
more..
int main()
{
// 프로세스의 기본힙을 구한다.
HANDLE h1 = GetProcessHeap();
// 새로운 힙을 만든다.. 동기화 되지 않게 하고..
// 메모리 할당 실패시 예외가 나오게 한다.
HANDLE h2 = HeapCreate( HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS,
1024*1024, // 초기크기
0 ); // 최대 크기( 0은 자동증가(Commit) )
// 이제 힙에서 메모리를 할당한다.
void* p1 = HeapAlloc( h1, HEAP_ZERO_MEMORY, 10 );
void* p2 = HeapAlloc( h2, HEAP_ZERO_MEMORY, 10 );
printf( "%p\n", p1 );
printf( "%p\n", p2 );
HeapFree( h1, 0, p1 );
HeapFree( h2, 0, p2 );
// 힙 파괴
HeapDestroy( h2 );
}
{
// 프로세스의 기본힙을 구한다.
HANDLE h1 = GetProcessHeap();
// 새로운 힙을 만든다.. 동기화 되지 않게 하고..
// 메모리 할당 실패시 예외가 나오게 한다.
HANDLE h2 = HeapCreate( HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS,
1024*1024, // 초기크기
0 ); // 최대 크기( 0은 자동증가(Commit) )
// 이제 힙에서 메모리를 할당한다.
void* p1 = HeapAlloc( h1, HEAP_ZERO_MEMORY, 10 );
void* p2 = HeapAlloc( h2, HEAP_ZERO_MEMORY, 10 );
printf( "%p\n", p1 );
printf( "%p\n", p2 );
HeapFree( h1, 0, p1 );
HeapFree( h2, 0, p2 );
// 힙 파괴
HeapDestroy( h2 );
}
more..
// 자신 전용의 힙을 사용하는 Node
class Node
{
static HANDLE my_heap;
static int count;
public:
void* operator new( size_t sz )
{
if( my_heap == 0 )
{
my_heap = HeapCreate( 0, 1024*1024, 0 );
}
void* p = HeapAlloc( my_heap, HEAP_ZERO_MEMORY, sz );
++count;
return p;
}
void operator delete( void* p )
{
HeapFree( my_heap, 0, p );
--count;
if( count == 0 ) HeapDestroy( my_heap );
}
};
HANDLE Node::my_heap = 0;
int Node::count = 0;
int main()
{
Node* p1 = new Node;
int* p2 = new int;
}
class Node
{
static HANDLE my_heap;
static int count;
public:
void* operator new( size_t sz )
{
if( my_heap == 0 )
{
my_heap = HeapCreate( 0, 1024*1024, 0 );
}
void* p = HeapAlloc( my_heap, HEAP_ZERO_MEMORY, sz );
++count;
return p;
}
void operator delete( void* p )
{
HeapFree( my_heap, 0, p );
--count;
if( count == 0 ) HeapDestroy( my_heap );
}
};
HANDLE Node::my_heap = 0;
int Node::count = 0;
int main()
{
Node* p1 = new Node;
int* p2 = new int;
}
3. 동적 TLS를 사용한 DLL ( strtok 문제 해결 )
more..
// 정적 TLS : LoadLibrary를 사용하게 되면 문제가 된다.
// __declspec(thread) char* buf = 0;
DWORD index = 0; // 동적 TLS index로 사용.
extern "C" _declspec(dllexport) void SetData( char* s )
{
char* buf = (char*) TlsGetValue( index );
strcpy( buf, s );
}
extern "C" _declspec(dllexport) void GetData( char* s )
{
char* buf = (char*) TlsGetValue( index );
strcpy( s, buf );
}
BOOL WINAPI DllMain( HANDLE hDll, // DLL 핸들, 결국 주소
DWORD r, // DllMain 이 호출된 이유
LPVOID how // DLL이 Load된 방식( 0이면 LoadLibrary 사용 )
)
{
char* buf = 0;
switch( r )
{
case DLL_PROCESS_ATTACH:
///////////////////////////////////////////////////////////////////////////////////
{
// 특정기능을 수행
foo();
// DLL을 자동으로 내린다.
// FreeLibrary( hDll ); // Dll이 내려가면 메모리에서 사라지므로 안됨.
// 강제로 dll를 내리고 스레드를 종료한다.
// 아래 함수를 만든이가 DLL안에서 스스로를 Free하는 기회를 주기 위해서.
FreeLibraryAndExitThread( hDll, 0 );
// DLL이 Load되면 동시에 스레드를 만든다.
// HANDLE h = CreateThread( 0, 0, foo, 0, 0, 0 ); // 바이러스 검사
// 새로운 스레드가 Wait에 막혀서 절대 실행될 수 없다.
// 주스레드가 아직 DllMain을 나가지 못했으므로 foo를 실행하는
// 새로운 스레드는 DllMain을 실행하기 위해 Block된 상태..
// WaitForSingleObject( h, INFINITE );
}
///////////////////////////////////////////////////////////////////////////////////
//buf = (char*)HeapAlloc( GetProcessHeap(), 0, 1000 ); // 기본힙으로부터 1000byte를 할당..
index = TlsAlloc(); // 동적 TLS에 빈슬롯 할당
// 주스레드를 위해서 메모리 할당.
buf = (char*)HeapAlloc( GetProcessHeap(), 0, 1000 );
// 주소를 TLS에 보관
TlsSetValue( index, (void*)buf );
printf( "DLL이 Load되었습니다. 주소 : %p\n", hDll );
printf( "%s\n", how ? "implicit linking" : "explicit linking"); // 명시적, 암시적 로드를 판단.!!
break;
case DLL_PROCESS_DETACH:
//HeapFree( GetProcessHeap(), 0, buf );
TlsFree( index );
printf( "DLL이 프로세스에서 해지 됩니다.\n" );
break;
case DLL_THREAD_ATTACH:
// 새로운 스레드가 생성 될 때마다 메모리를 할당해서 Thread-Safe를 보장!!
buf = (char*)HeapAlloc( GetProcessHeap(), 0, 1000 );
TlsSetValue( index, (void*)buf );
printf( "스레드가 생성됩니다.\n" );
break;
case DLL_THREAD_DETACH:
buf = (char*) TlsGetValue( index );
HeapFree( GetProcessHeap(), 0, buf );
printf( "스레드가 파괴됩니다.\n" );
break;
}
return TRUE;
}
// __declspec(thread) char* buf = 0;
DWORD index = 0; // 동적 TLS index로 사용.
extern "C" _declspec(dllexport) void SetData( char* s )
{
char* buf = (char*) TlsGetValue( index );
strcpy( buf, s );
}
extern "C" _declspec(dllexport) void GetData( char* s )
{
char* buf = (char*) TlsGetValue( index );
strcpy( s, buf );
}
BOOL WINAPI DllMain( HANDLE hDll, // DLL 핸들, 결국 주소
DWORD r, // DllMain 이 호출된 이유
LPVOID how // DLL이 Load된 방식( 0이면 LoadLibrary 사용 )
)
{
char* buf = 0;
switch( r )
{
case DLL_PROCESS_ATTACH:
///////////////////////////////////////////////////////////////////////////////////
{
// 특정기능을 수행
foo();
// DLL을 자동으로 내린다.
// FreeLibrary( hDll ); // Dll이 내려가면 메모리에서 사라지므로 안됨.
// 강제로 dll를 내리고 스레드를 종료한다.
// 아래 함수를 만든이가 DLL안에서 스스로를 Free하는 기회를 주기 위해서.
FreeLibraryAndExitThread( hDll, 0 );
// DLL이 Load되면 동시에 스레드를 만든다.
// HANDLE h = CreateThread( 0, 0, foo, 0, 0, 0 ); // 바이러스 검사
// 새로운 스레드가 Wait에 막혀서 절대 실행될 수 없다.
// 주스레드가 아직 DllMain을 나가지 못했으므로 foo를 실행하는
// 새로운 스레드는 DllMain을 실행하기 위해 Block된 상태..
// WaitForSingleObject( h, INFINITE );
}
///////////////////////////////////////////////////////////////////////////////////
//buf = (char*)HeapAlloc( GetProcessHeap(), 0, 1000 ); // 기본힙으로부터 1000byte를 할당..
index = TlsAlloc(); // 동적 TLS에 빈슬롯 할당
// 주스레드를 위해서 메모리 할당.
buf = (char*)HeapAlloc( GetProcessHeap(), 0, 1000 );
// 주소를 TLS에 보관
TlsSetValue( index, (void*)buf );
printf( "DLL이 Load되었습니다. 주소 : %p\n", hDll );
printf( "%s\n", how ? "implicit linking" : "explicit linking"); // 명시적, 암시적 로드를 판단.!!
break;
case DLL_PROCESS_DETACH:
//HeapFree( GetProcessHeap(), 0, buf );
TlsFree( index );
printf( "DLL이 프로세스에서 해지 됩니다.\n" );
break;
case DLL_THREAD_ATTACH:
// 새로운 스레드가 생성 될 때마다 메모리를 할당해서 Thread-Safe를 보장!!
buf = (char*)HeapAlloc( GetProcessHeap(), 0, 1000 );
TlsSetValue( index, (void*)buf );
printf( "스레드가 생성됩니다.\n" );
break;
case DLL_THREAD_DETACH:
buf = (char*) TlsGetValue( index );
HeapFree( GetProcessHeap(), 0, buf );
printf( "스레드가 파괴됩니다.\n" );
break;
}
return TRUE;
}
4. DLL이 로드되는 과정 보기(위예제랑 연동)
more..
DWORD WINAPI foo( void* p )
{
Sleep(5000);
return 0;
}
int main()
{
getch();
HMODULE hDll = LoadLibrary( "DllMain.dll" );
CloseHandle( CreateThread( 0, 0, foo, 0, 0, 0 ) ); // 스레드 생성
getch();
FreeLibrary( hDll );
getch();
}
{
Sleep(5000);
return 0;
}
int main()
{
getch();
HMODULE hDll = LoadLibrary( "DllMain.dll" );
CloseHandle( CreateThread( 0, 0, foo, 0, 0, 0 ) ); // 스레드 생성
getch();
FreeLibrary( hDll );
getch();
}
5. Hook Dll 만들기
more..
HMODULE g_hDll; // 훅 함수를 가진 DLL의 핸들
#pragma data_seg( "AAA" )
HHOOK g_hHook = 0; // 훅 핸들
#pragma data_seg()
#pragma comment(linker, "/section:AAA,RWS")
BOOL WINAPI DllMain( HANDLE h, DWORD r, LPVOID how )
{
if ( r == DLL_PROCESS_ATTACH )
{
g_hDll = (HMODULE)h;
}
return TRUE;
}
// 훅필터 함수
LRESULT CALLBACK GetMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
{
if ( nCode == HC_ACTION ) // 메시지를 꺼내 가는중..
{
MSG* pMsg = (MSG*)lParam; // 꺼내가고 있는 메시지.
if ( pMsg->message == WM_CHAR )
{
// 다른 곳으로 보낸다.( N/W또는 IPC사용, 또는 파일로 저장 )
HWND hwnd = FindWindow( 0, "Friend" );
PostMessage( hwnd, WM_USER+100, pMsg->wParam, pMsg->lParam );
}
}
// 다음 번 훅필터 함수에게 전달한다.( Hook Chain )
return CallNextHookEx( g_hHook, nCode, wParam, lParam );
}
// 훅을 설치하는 함수
extern "C" __declspec(dllexport) void Install( DWORD tid )
{
g_hHook = SetWindowsHookEx( WH_GETMESSAGE, // 훅의 종료(15가지)
GetMsgProc, // 훅함수
g_hDll, // 훅함수를 가진 DLL핸들(주소)
tid ); // 훅을 설치할 스레드( 0:Global hook )
}
extern "C" __declspec(dllexport) void Uninstall()
{
UnhookWindowsHookEx( g_hHook );
}
#pragma data_seg( "AAA" )
HHOOK g_hHook = 0; // 훅 핸들
#pragma data_seg()
#pragma comment(linker, "/section:AAA,RWS")
BOOL WINAPI DllMain( HANDLE h, DWORD r, LPVOID how )
{
if ( r == DLL_PROCESS_ATTACH )
{
g_hDll = (HMODULE)h;
}
return TRUE;
}
// 훅필터 함수
LRESULT CALLBACK GetMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
{
if ( nCode == HC_ACTION ) // 메시지를 꺼내 가는중..
{
MSG* pMsg = (MSG*)lParam; // 꺼내가고 있는 메시지.
if ( pMsg->message == WM_CHAR )
{
// 다른 곳으로 보낸다.( N/W또는 IPC사용, 또는 파일로 저장 )
HWND hwnd = FindWindow( 0, "Friend" );
PostMessage( hwnd, WM_USER+100, pMsg->wParam, pMsg->lParam );
}
}
// 다음 번 훅필터 함수에게 전달한다.( Hook Chain )
return CallNextHookEx( g_hHook, nCode, wParam, lParam );
}
// 훅을 설치하는 함수
extern "C" __declspec(dllexport) void Install( DWORD tid )
{
g_hHook = SetWindowsHookEx( WH_GETMESSAGE, // 훅의 종료(15가지)
GetMsgProc, // 훅함수
g_hDll, // 훅함수를 가진 DLL핸들(주소)
tid ); // 훅을 설치할 스레드( 0:Global hook )
}
extern "C" __declspec(dllexport) void Uninstall()
{
UnhookWindowsHookEx( g_hHook );
}
6. Hook 한 메시지 읽어오기( Friend)
more..
typedef void(*INSTALL)(DWORD);
typedef void(*UNINSTALL)();
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HMODULE hDll;
static INSTALL Install;
static UNINSTALL Uninstall;
static HWND hEdit;
switch( msg )
{
case WM_CREATE:
hEdit = CreateWindow( "edit", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE,
10, 10, 500, 500, hwnd, (HMENU)1, 0, 0 );
hDll = LoadLibrary( "HookDll.dll" );
Install = (INSTALL)GetProcAddress( hDll, "Install" );
Uninstall = (UNINSTALL)GetProcAddress( hDll, "Uninstall" );
Install(0); // global hook 설치
return 0;
case WM_USER+100:
// Edit에 WM_CHAR를 보내면 알아서 출력해 줄것이다.
SendMessage( hEdit, WM_CHAR, wParam, lParam );
return 0;
case WM_DESTROY:
Uninstall();
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
typedef void(*UNINSTALL)();
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HMODULE hDll;
static INSTALL Install;
static UNINSTALL Uninstall;
static HWND hEdit;
switch( msg )
{
case WM_CREATE:
hEdit = CreateWindow( "edit", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE,
10, 10, 500, 500, hwnd, (HMENU)1, 0, 0 );
hDll = LoadLibrary( "HookDll.dll" );
Install = (INSTALL)GetProcAddress( hDll, "Install" );
Uninstall = (UNINSTALL)GetProcAddress( hDll, "Uninstall" );
Install(0); // global hook 설치
return 0;
case WM_USER+100:
// Edit에 WM_CHAR를 보내면 알아서 출력해 줄것이다.
SendMessage( hEdit, WM_CHAR, wParam, lParam );
return 0;
case WM_DESTROY:
Uninstall();
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}