1. 가상메모리 기본( VirtualAlloc )
2. MMF 기본
3. MMF 를 이용한 그리기 통신( B가 A에게 오버헤드를 발생시킨다.ㅜ_ㅜ )
4. DLL Inject
more..
int main()
{
const int size = 1024 * 1024 * 100; // 100M
char* p1 = (char*)VirtualAlloc( (void*)0, // 원하는 주소(64k배수), 자동으로 할당 0
size*15, // 원하는 크기(4k 단위)
MEM_RESERVE, // 예약만
PAGE_NOACCESS ); // 보호 속성(어짜피 접근못하므로 NOACCESS)
printf( "예약된 주소 : %p\n", p1 );
//*p1 = 'a'; // 예약만 된 주소를 사용하는 경우. - RunTime Error 발생..
char* p2 = p1;
for( int i = 0; i < 15; ++i )
{
getch();
void* p3 = VirtualAlloc( p2, size, MEM_COMMIT, PAGE_READWRITE );
printf( "확정된 메모리 : %d\n", p3 );
p2 = p2 + size; // 다음 확정할 주소
}
VirtualFree( p1, size*15, MEM_DECOMMIT ); // 다시 예약 상태로
VirtualFree( p1, 0, MEM_RELEASE ); // 다시 Free상태로
// MEM_RELEASE 지정시 반드시 두번째인자는 0!!
}
{
const int size = 1024 * 1024 * 100; // 100M
char* p1 = (char*)VirtualAlloc( (void*)0, // 원하는 주소(64k배수), 자동으로 할당 0
size*15, // 원하는 크기(4k 단위)
MEM_RESERVE, // 예약만
PAGE_NOACCESS ); // 보호 속성(어짜피 접근못하므로 NOACCESS)
printf( "예약된 주소 : %p\n", p1 );
//*p1 = 'a'; // 예약만 된 주소를 사용하는 경우. - RunTime Error 발생..
char* p2 = p1;
for( int i = 0; i < 15; ++i )
{
getch();
void* p3 = VirtualAlloc( p2, size, MEM_COMMIT, PAGE_READWRITE );
printf( "확정된 메모리 : %d\n", p3 );
p2 = p2 + size; // 다음 확정할 주소
}
VirtualFree( p1, size*15, MEM_DECOMMIT ); // 다시 예약 상태로
VirtualFree( p1, 0, MEM_RELEASE ); // 다시 Free상태로
// MEM_RELEASE 지정시 반드시 두번째인자는 0!!
}
2. MMF 기본
more..
/////////////////////////////////////////////////////////////////////////////////////
// exe 로드해서 IMAGE_DOS_HEADER 읽기
int main()
{
// MMF 1단계 - 화일 Create 또는 Open
HANDLE hFile = CreateFile(
"c:\\windows\\system32\\calc.exe",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0 );
// MMF 2단계 - 화일 매핑 KO 생성
HANDLE hMap = CreateFileMapping( hFile, // 연결할 파일
0, // 매핑KO( 섹션 Object ) 보안 속성
PAGE_READONLY, //
0, sizeof(IMAGE_DOS_HEADER), // 매핑할 크기
"map" ); // 매핑 객체 이름
// MMF 3단계 - 매핑 객체를 사용해서 화일을 가상주소와 연결한다.
IMAGE_DOS_HEADER* p = (IMAGE_DOS_HEADER*) MapViewOfFileEx( hMap, FILE_MAP_READ,
0, 0, // Offset( 파일 생성시는 무조건 0 기존파일 Open시에만 적용 )
0, // 크기( 0 매핑 객체에 지정된 크기를 사용 )
(void*)0x00600000 ); // 원하는 주소
if ( p == 0 ) printf( "error\n" );
else
{
printf( "매핑된 주소 : %p\n", p );
printf( "%x\n", p->e_magic ); // 모든 실행 파일은 "MZ" 로 시작한다.
}
UnmapViewOfFile( p );
CloseHandle( hMap );
CloseHandle( hFile );
}
/////////////////////////////////////////////////////////////////////////////////////
// FILE 로드해서 버퍼처럼 쓰기~
int main()
{
// MMF 1단계 - 화일 Create 또는 Open
HANDLE hFile = CreateFile( "a.txt", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
0,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0 );
// MMF 2단계 - 화일 매핑 KO 생성
HANDLE hMap = CreateFileMapping( hFile, // 연결할 파일
0, // 매핑KO( 섹션 Object ) 보안 속성
PAGE_READWRITE, //
0, sizeof(IMAGE_DOS_HEADER), // 매핑할 크기
"map" ); // 매핑 객체 이름
// MMF 3단계 - 매핑 객체를 사용해서 화일을 가상주소와 연결한다.
char* p = (char*) MapViewOfFileEx( hMap, FILE_MAP_WRITE,
0, 0, // Offset( 파일 생성시는 무조건 0 기존파일 Open시에만 적용 )
0, // 크기( 0 매핑 객체에 지정된 크기를 사용 )
(void*)0x00600000 ); // 원하는 주소
if ( p == 0 ) printf( "error\n" );
else
{
printf( "매핑된 주소 : %p\n", p );
strcpy( p, "Hello" ); // 파일에 출력
p[40] = 'C';
}
UnmapViewOfFile( p );
CloseHandle( hMap );
CloseHandle( hFile );
}
// exe 로드해서 IMAGE_DOS_HEADER 읽기
int main()
{
// MMF 1단계 - 화일 Create 또는 Open
HANDLE hFile = CreateFile(
"c:\\windows\\system32\\calc.exe",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0 );
// MMF 2단계 - 화일 매핑 KO 생성
HANDLE hMap = CreateFileMapping( hFile, // 연결할 파일
0, // 매핑KO( 섹션 Object ) 보안 속성
PAGE_READONLY, //
0, sizeof(IMAGE_DOS_HEADER), // 매핑할 크기
"map" ); // 매핑 객체 이름
// MMF 3단계 - 매핑 객체를 사용해서 화일을 가상주소와 연결한다.
IMAGE_DOS_HEADER* p = (IMAGE_DOS_HEADER*) MapViewOfFileEx( hMap, FILE_MAP_READ,
0, 0, // Offset( 파일 생성시는 무조건 0 기존파일 Open시에만 적용 )
0, // 크기( 0 매핑 객체에 지정된 크기를 사용 )
(void*)0x00600000 ); // 원하는 주소
if ( p == 0 ) printf( "error\n" );
else
{
printf( "매핑된 주소 : %p\n", p );
printf( "%x\n", p->e_magic ); // 모든 실행 파일은 "MZ" 로 시작한다.
}
UnmapViewOfFile( p );
CloseHandle( hMap );
CloseHandle( hFile );
}
/////////////////////////////////////////////////////////////////////////////////////
// FILE 로드해서 버퍼처럼 쓰기~
int main()
{
// MMF 1단계 - 화일 Create 또는 Open
HANDLE hFile = CreateFile( "a.txt", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
0,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0 );
// MMF 2단계 - 화일 매핑 KO 생성
HANDLE hMap = CreateFileMapping( hFile, // 연결할 파일
0, // 매핑KO( 섹션 Object ) 보안 속성
PAGE_READWRITE, //
0, sizeof(IMAGE_DOS_HEADER), // 매핑할 크기
"map" ); // 매핑 객체 이름
// MMF 3단계 - 매핑 객체를 사용해서 화일을 가상주소와 연결한다.
char* p = (char*) MapViewOfFileEx( hMap, FILE_MAP_WRITE,
0, 0, // Offset( 파일 생성시는 무조건 0 기존파일 Open시에만 적용 )
0, // 크기( 0 매핑 객체에 지정된 크기를 사용 )
(void*)0x00600000 ); // 원하는 주소
if ( p == 0 ) printf( "error\n" );
else
{
printf( "매핑된 주소 : %p\n", p );
strcpy( p, "Hello" ); // 파일에 출력
p[40] = 'C';
}
UnmapViewOfFile( p );
CloseHandle( hMap );
CloseHandle( hFile );
}
3. MMF 를 이용한 그리기 통신( B가 A에게 오버헤드를 발생시킨다.ㅜ_ㅜ )
more..
//-------------------------------------------------------------------------------
// A.cpp - 좌표를 pagefile에 써준다.
struct LINE
{
POINTS ptFrom;
POINTS ptTo;
};
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HANDLE hEvent, hMap, hEvent2;
static POINTS ptFrom, ptTo;
static LINE* pLine;
switch( msg )
{
case WM_CREATE:
{
hEvent = CreateEvent( 0, 0, 0, "e1" );
hEvent2 = CreateEvent( 0, 0, TRUE, "e2" );
// 매핑 객체 생성
hMap = CreateFileMapping( (HANDLE)-1, // Page 화일을 사용하라.
0, PAGE_READWRITE,
0, sizeof(LINE), "map" );
pLine = (LINE*) MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 );
}
return 0;
case WM_LBUTTONDOWN:
ptFrom = ptTo = MAKEPOINTS( lParam );
return 0;
case WM_MOUSEMOVE:
if( wParam & MK_LBUTTON )
{
POINTS pt = MAKEPOINTS( lParam );
HDC hdc = GetDC( hwnd );
MoveToEx( hdc, ptFrom.x, ptFrom.y, 0 );
LineTo ( hdc, pt.x, pt.y );
ReleaseDC( hwnd, hdc );
// MMF에 넣는다.
WaitForSingleObject( hEvent2, INFINITE ); // 꺼내 갔는가를 확인..
pLine->ptFrom = ptFrom;
pLine->ptTo = pt;
// Event Signal
SetEvent( hEvent );
ptFrom = pt;
}
return 0;
case WM_DESTROY:
UnmapViewOfFile( pLine );
CloseHandle( hEvent );
CloseHandle( hMap );
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
//-------------------------------------------------------------------------------
// B.cpp - A.cpp 에서 입력한 pagefile을 읽는다.
struct LINE
{
POINTS ptFrom;
POINTS ptTo;
};
DWORD WINAPI Work( void* p )
{
HWND hwnd = (HWND)p;
HANDLE hEvent = OpenEvent( EVENT_ALL_ACCESS, 0, "e1" );
HANDLE hEvent2 = OpenEvent( EVENT_ALL_ACCESS, 0, "e2" );
HANDLE hMap = OpenFileMapping( FILE_MAP_ALL_ACCESS, 0, "map" );
LINE* pLine = (LINE*) MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 );
while( 1 )
{
WaitForSingleObject( hEvent, INFINITE );
// 약간의 지연이 발생..
Sleep(10);
// 이제 MMF에서 꺼내서 그린다.
HDC hdc = GetDC( hwnd );
MoveToEx( hdc, pLine->ptFrom.x, pLine->ptFrom.y, 0 );
LineTo( hdc, pLine->ptTo.x, pLine->ptTo.y );
// 꺼내 갔음을 알려준다.
SetEvent( hEvent2 );
ReleaseDC( hwnd, hdc );
}
return 0;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_CREATE:
CloseHandle( CreateThread( 0, 0, Work, (void*)hwnd, 0, 0 ) );
return 0;
case WM_LBUTTONDOWN:
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
// A.cpp - 좌표를 pagefile에 써준다.
struct LINE
{
POINTS ptFrom;
POINTS ptTo;
};
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HANDLE hEvent, hMap, hEvent2;
static POINTS ptFrom, ptTo;
static LINE* pLine;
switch( msg )
{
case WM_CREATE:
{
hEvent = CreateEvent( 0, 0, 0, "e1" );
hEvent2 = CreateEvent( 0, 0, TRUE, "e2" );
// 매핑 객체 생성
hMap = CreateFileMapping( (HANDLE)-1, // Page 화일을 사용하라.
0, PAGE_READWRITE,
0, sizeof(LINE), "map" );
pLine = (LINE*) MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 );
}
return 0;
case WM_LBUTTONDOWN:
ptFrom = ptTo = MAKEPOINTS( lParam );
return 0;
case WM_MOUSEMOVE:
if( wParam & MK_LBUTTON )
{
POINTS pt = MAKEPOINTS( lParam );
HDC hdc = GetDC( hwnd );
MoveToEx( hdc, ptFrom.x, ptFrom.y, 0 );
LineTo ( hdc, pt.x, pt.y );
ReleaseDC( hwnd, hdc );
// MMF에 넣는다.
WaitForSingleObject( hEvent2, INFINITE ); // 꺼내 갔는가를 확인..
pLine->ptFrom = ptFrom;
pLine->ptTo = pt;
// Event Signal
SetEvent( hEvent );
ptFrom = pt;
}
return 0;
case WM_DESTROY:
UnmapViewOfFile( pLine );
CloseHandle( hEvent );
CloseHandle( hMap );
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
//-------------------------------------------------------------------------------
// B.cpp - A.cpp 에서 입력한 pagefile을 읽는다.
struct LINE
{
POINTS ptFrom;
POINTS ptTo;
};
DWORD WINAPI Work( void* p )
{
HWND hwnd = (HWND)p;
HANDLE hEvent = OpenEvent( EVENT_ALL_ACCESS, 0, "e1" );
HANDLE hEvent2 = OpenEvent( EVENT_ALL_ACCESS, 0, "e2" );
HANDLE hMap = OpenFileMapping( FILE_MAP_ALL_ACCESS, 0, "map" );
LINE* pLine = (LINE*) MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 );
while( 1 )
{
WaitForSingleObject( hEvent, INFINITE );
// 약간의 지연이 발생..
Sleep(10);
// 이제 MMF에서 꺼내서 그린다.
HDC hdc = GetDC( hwnd );
MoveToEx( hdc, pLine->ptFrom.x, pLine->ptFrom.y, 0 );
LineTo( hdc, pLine->ptTo.x, pLine->ptTo.y );
// 꺼내 갔음을 알려준다.
SetEvent( hEvent2 );
ReleaseDC( hwnd, hdc );
}
return 0;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_CREATE:
CloseHandle( CreateThread( 0, 0, Work, (void*)hwnd, 0, 0 ) );
return 0;
case WM_LBUTTONDOWN:
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
4. DLL Inject
more..
// spy.dll 만들기~
WNDPROC old;
// 계산기의 메세지 처리함수를 가로챌 함수
LRESULT CALLBACK foo( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_COMMAND: // 메뉴 선택
switch( LOWORD(wParam) )
{
case 304: // "공학용" 메뉴
MessageBox( 0, "^^", "", MB_OK );
return 0;
}
break;
}
// 나머지 메세지는 모두 원래의 함수로 보낸다.
return CallWindowProc( old, hwnd, msg, wParam, lParam );
}
// DLL이 프로세스에 매핑될때 자동으로 호출되는 함수
BOOL WINAPI DllMain( HANDLE h, DWORD r, LPVOID how )
{
if ( r == DLL_PROCESS_ATTACH )
{
HWND hwnd = FindWindow( 0, "계산기" );
old = (WNDPROC)SetWindowLong( hwnd, GWL_WNDPROC, (LONG)foo );
}
return TRUE; // 반드시 TRUE를 리턴.
}
////////////////////////////////////////////////////////////////////////////////
// DLLInject.cpp
void DLLInject( DWORD pid, const char* path )
{
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, 0, pid );
///////////////////////////////////////////////////////////
// LoadLibrary 의 주소를 찾는다.
HMODULE hDll = GetModuleHandle( "Kernel32.dll" );
PTHREAD_START_ROUTINE f = (PTHREAD_START_ROUTINE)
GetProcAddress( hDll, "LoadLibraryA" );
// PTHREAD_START_ROUTINE 은 미리 정의된 스레드 함수 포인터 type이다.
void* p = VirtualAllocEx( hProcess, 0, strlen(path)+1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
// Inject 할 DLL의 경로를 계산기 메모리에 복사해 놓는다.
DWORD len;
WriteProcessMemory( hProcess, p, path, strlen(path)+1, &len );
///////////////////////////////////////////////////////////
// 다른 프로세스에 스레드를 생성한다.
HANDLE hThread = CreateRemoteThread( hProcess, 0, 0,
f, (void*)p, // 함수, 파라미터
0, 0 );
}
int main()
{
HWND hwnd = FindWindow( 0, "계산기" );
if ( hwnd == 0 )
{
printf( "계산기 부터 실행하세요..\n" );
return 0;
}
// 계산기 프로세스에 DLL을 강제로 넣는다.
DWORD pid;
DWORD tid = GetWindowThreadProcessId( hwnd, &pid );
DLLInject( pid, "C:\\spy.dll" );
}
WNDPROC old;
// 계산기의 메세지 처리함수를 가로챌 함수
LRESULT CALLBACK foo( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_COMMAND: // 메뉴 선택
switch( LOWORD(wParam) )
{
case 304: // "공학용" 메뉴
MessageBox( 0, "^^", "", MB_OK );
return 0;
}
break;
}
// 나머지 메세지는 모두 원래의 함수로 보낸다.
return CallWindowProc( old, hwnd, msg, wParam, lParam );
}
// DLL이 프로세스에 매핑될때 자동으로 호출되는 함수
BOOL WINAPI DllMain( HANDLE h, DWORD r, LPVOID how )
{
if ( r == DLL_PROCESS_ATTACH )
{
HWND hwnd = FindWindow( 0, "계산기" );
old = (WNDPROC)SetWindowLong( hwnd, GWL_WNDPROC, (LONG)foo );
}
return TRUE; // 반드시 TRUE를 리턴.
}
////////////////////////////////////////////////////////////////////////////////
// DLLInject.cpp
void DLLInject( DWORD pid, const char* path )
{
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, 0, pid );
///////////////////////////////////////////////////////////
// LoadLibrary 의 주소를 찾는다.
HMODULE hDll = GetModuleHandle( "Kernel32.dll" );
PTHREAD_START_ROUTINE f = (PTHREAD_START_ROUTINE)
GetProcAddress( hDll, "LoadLibraryA" );
// PTHREAD_START_ROUTINE 은 미리 정의된 스레드 함수 포인터 type이다.
void* p = VirtualAllocEx( hProcess, 0, strlen(path)+1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
// Inject 할 DLL의 경로를 계산기 메모리에 복사해 놓는다.
DWORD len;
WriteProcessMemory( hProcess, p, path, strlen(path)+1, &len );
///////////////////////////////////////////////////////////
// 다른 프로세스에 스레드를 생성한다.
HANDLE hThread = CreateRemoteThread( hProcess, 0, 0,
f, (void*)p, // 함수, 파라미터
0, 0 );
}
int main()
{
HWND hwnd = FindWindow( 0, "계산기" );
if ( hwnd == 0 )
{
printf( "계산기 부터 실행하세요..\n" );
return 0;
}
// 계산기 프로세스에 DLL을 강제로 넣는다.
DWORD pid;
DWORD tid = GetWindowThreadProcessId( hwnd, &pid );
DLLInject( pid, "C:\\spy.dll" );
}