1.GetMessageBoxA 의 후킹~
2. Debug Help API 를 이용한 후킹~
3. __try, __except 기초
4. C++ throw의 __except
5. STH( Structure Termination Handling ) __try, __finally ( 구조화된 종료 처리 )
1) 개념
2) 응용 ( 자원관리를 __finally 에서 담당해준다.!!! )
6. SEH 를 응용해서 메모리 할당 해보기. ( 일명 : Big Shell )
7. API Hooking ( SetTimer를 바꿔치기 해보자 - 미완성 ㅜ_ㅜ )
1) DLL ( Inject 할 Dll )
2) Inject ( DLL을 Inject 하기.. )
more..
// API Hooking 의 개념 - DLL 함수 호출의 원리
typedef UINT ( WINAPI* F )( HWND, PCSTR, PCSTR, UINT );
UINT WINAPI foo( HWND hwnd, PCSTR msg, PCSTR caption, UINT btn )
{
printf( "foo : %x, %s, %s \n", hwnd, msg, caption );
// 원래 함수로 다시 보낸다.
// MessageBoxA(); // 재귀호출을 한다..
HMODULE hDll = GetModuleHandle("User32.dll");
F f = (F)GetProcAddress( hDll, "MessageBoxA" );
return f( hwnd, msg, caption, btn );
}
int main()
{
printf( "%p\n", GetModuleHandle("User32.dll") );
printf( "%p\n", MessageBoxA );
// .idata section 에서 MessageBoxA의 주소를 담은 곳을 foo의 주소로 변경한다.
// 주소에 타입없이 대입시킨다면 호출시 읽어 올수가 없다.
// 그러므로 int 로 강제 형변환 해준다.
*((int*)(0x00418338)) = (int)foo;
MessageBoxA( 0, "Hello", "", MB_OK); // User32.dll 에 있다.
}
typedef UINT ( WINAPI* F )( HWND, PCSTR, PCSTR, UINT );
UINT WINAPI foo( HWND hwnd, PCSTR msg, PCSTR caption, UINT btn )
{
printf( "foo : %x, %s, %s \n", hwnd, msg, caption );
// 원래 함수로 다시 보낸다.
// MessageBoxA(); // 재귀호출을 한다..
HMODULE hDll = GetModuleHandle("User32.dll");
F f = (F)GetProcAddress( hDll, "MessageBoxA" );
return f( hwnd, msg, caption, btn );
}
int main()
{
printf( "%p\n", GetModuleHandle("User32.dll") );
printf( "%p\n", MessageBoxA );
// .idata section 에서 MessageBoxA의 주소를 담은 곳을 foo의 주소로 변경한다.
// 주소에 타입없이 대입시킨다면 호출시 읽어 올수가 없다.
// 그러므로 int 로 강제 형변환 해준다.
*((int*)(0x00418338)) = (int)foo;
MessageBoxA( 0, "Hello", "", MB_OK); // User32.dll 에 있다.
}
2. Debug Help API 를 이용한 후킹~
more..
#include "Dbghelp.h"
#pragma comment( lib, "Dbghelp.lib" )
// 제프리책 853p 에 있는 코드들~
void Replace( HMODULE hDll, // exe의 주소
char* name, // 후킹할 함수를 가진 dll의 이름
PROC oldfunc, // 원래 API함수의 주소
PROC newfunc ) // 후킹할 함수
{
// .exe에서 .idata section의 주소를 얻는다.
ULONG sz;
IMAGE_IMPORT_DESCRIPTOR* pImage = (IMAGE_IMPORT_DESCRIPTOR*)
ImageDirectoryEntryToData( hDll, // 모듈 주소
TRUE, // Mapping?
IMAGE_DIRECTORY_ENTRY_IMPORT,
&sz );
printf( ".idata의 주소 : %p\n", pImage );
// 2. User32.dll 의 항목을 구한다.
for( ; pImage->Name; ++pImage )
{
char* p = (char*)hDll + pImage->Name;
if( strcmpi( p, name ) == 0 ) break; //찾은경우
}
if ( pImage->Name == 0 )
{
printf( "User32.dll을 import 하지 않습니다.\n" );
return;
}
printf( "User32.dll를 관리하는 구조체 주소 : %p\n", pImage );
// 3. Thunk Table에서 원하는 함수를 찾는다.
IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)
( (char*)hDll + pImage->FirstThunk );
// 4. 이제 함수를 찾아서 새로운 함수 주소를 덮어 쓴다.
for ( ; pThunk->u1.Function; ++pThunk )
{
if( (PROC)(pThunk->u1.Function) == oldfunc )
{
PROC* p = (PROC*)&(pThunk->u1.Function);
// Release 모드에서는 가상주소를 보호해준다.
// 그러므로 보호속성을 R/W로 변경해야 한다.
DWORD old;
VirtualProtect( p, sizeof(PROC), PAGE_READWRITE, &old );
// 쓰기를 할때는 WriteProcessMemory() 함수를 사용핮.
WriteProcessMemory( GetCurrentProcess(), p, &newfunc, sizeof(PROC), 0 );
}
}
}
typedef UINT ( WINAPI* F )( HWND, PCSTR, PCSTR, UINT );
UINT WINAPI foo( HWND hwnd, PCSTR msg, PCSTR caption, UINT btn )
{
printf( "foo : %x, %s, %s \n", hwnd, msg, caption );
// 원래 함수로 다시 보낸다.
// MessageBoxA(); // 재귀호출을 한다..
HMODULE hDll = GetModuleHandle("User32.dll");
F f = (F)GetProcAddress( hDll, "MessageBoxA" );
return f( hwnd, msg, caption, btn );
}
void Setup()
{
Replace( GetModuleHandle(0), "User32.dll", (PROC)MessageBoxA, (PROC)foo );
}
int main()
{
Setup();
printf( "%p\n", GetModuleHandle("User32.dll") );
printf( "%p\n", MessageBoxA ); // Release 모드에서는 이 순간 MessageBoxA의 주소를
// ECX 레지스터에 보관해둔다.
// Replace( GetModuleHandle(0), "User32.dll", (PROC)MessageBoxA, (PROC)foo );
MessageBoxA( 0, "Hello", "", MB_OK); // User32.dll 에 있다.
}
#pragma comment( lib, "Dbghelp.lib" )
// 제프리책 853p 에 있는 코드들~
void Replace( HMODULE hDll, // exe의 주소
char* name, // 후킹할 함수를 가진 dll의 이름
PROC oldfunc, // 원래 API함수의 주소
PROC newfunc ) // 후킹할 함수
{
// .exe에서 .idata section의 주소를 얻는다.
ULONG sz;
IMAGE_IMPORT_DESCRIPTOR* pImage = (IMAGE_IMPORT_DESCRIPTOR*)
ImageDirectoryEntryToData( hDll, // 모듈 주소
TRUE, // Mapping?
IMAGE_DIRECTORY_ENTRY_IMPORT,
&sz );
printf( ".idata의 주소 : %p\n", pImage );
// 2. User32.dll 의 항목을 구한다.
for( ; pImage->Name; ++pImage )
{
char* p = (char*)hDll + pImage->Name;
if( strcmpi( p, name ) == 0 ) break; //찾은경우
}
if ( pImage->Name == 0 )
{
printf( "User32.dll을 import 하지 않습니다.\n" );
return;
}
printf( "User32.dll를 관리하는 구조체 주소 : %p\n", pImage );
// 3. Thunk Table에서 원하는 함수를 찾는다.
IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)
( (char*)hDll + pImage->FirstThunk );
// 4. 이제 함수를 찾아서 새로운 함수 주소를 덮어 쓴다.
for ( ; pThunk->u1.Function; ++pThunk )
{
if( (PROC)(pThunk->u1.Function) == oldfunc )
{
PROC* p = (PROC*)&(pThunk->u1.Function);
// Release 모드에서는 가상주소를 보호해준다.
// 그러므로 보호속성을 R/W로 변경해야 한다.
DWORD old;
VirtualProtect( p, sizeof(PROC), PAGE_READWRITE, &old );
// 쓰기를 할때는 WriteProcessMemory() 함수를 사용핮.
WriteProcessMemory( GetCurrentProcess(), p, &newfunc, sizeof(PROC), 0 );
}
}
}
typedef UINT ( WINAPI* F )( HWND, PCSTR, PCSTR, UINT );
UINT WINAPI foo( HWND hwnd, PCSTR msg, PCSTR caption, UINT btn )
{
printf( "foo : %x, %s, %s \n", hwnd, msg, caption );
// 원래 함수로 다시 보낸다.
// MessageBoxA(); // 재귀호출을 한다..
HMODULE hDll = GetModuleHandle("User32.dll");
F f = (F)GetProcAddress( hDll, "MessageBoxA" );
return f( hwnd, msg, caption, btn );
}
void Setup()
{
Replace( GetModuleHandle(0), "User32.dll", (PROC)MessageBoxA, (PROC)foo );
}
int main()
{
Setup();
printf( "%p\n", GetModuleHandle("User32.dll") );
printf( "%p\n", MessageBoxA ); // Release 모드에서는 이 순간 MessageBoxA의 주소를
// ECX 레지스터에 보관해둔다.
// Replace( GetModuleHandle(0), "User32.dll", (PROC)MessageBoxA, (PROC)foo );
MessageBoxA( 0, "Hello", "", MB_OK); // User32.dll 에 있다.
}
3. __try, __except 기초
more..
// SEH : structual Exception Handling
int n = 0;
DWORD Filter( DWORD code )
{
if ( code == EXCEPTION_INT_DIVIDE_BY_ZERO ) // 0xc0000094
{
printf( "0으로 나누는 예외 발생. 다른값을 입력 : " );
scanf("%d", &n);
return -1; // 예외의 원인을 수정했으므로 다시 실행해 본다.
}
return 1;
}
int main()
{
int s = 0;
__try
{
s = 10 / n ; // Code : 0xc0000094
char* p = 0;
*p = 'A'; // access - violation Code : 0xc0000005
printf( "%d\n", s );
}
// 1: 핸들러 수행, -1: 예외난곳을 다시 실행 0: 외부의 __try블록으로 전달.
__except( Filter( GetExceptionCode() ) )
{
printf( "예외발생: %x\n", GetExceptionCode() );
}
printf("프로그램은 계속 실행\n");
}
int n = 0;
DWORD Filter( DWORD code )
{
if ( code == EXCEPTION_INT_DIVIDE_BY_ZERO ) // 0xc0000094
{
printf( "0으로 나누는 예외 발생. 다른값을 입력 : " );
scanf("%d", &n);
return -1; // 예외의 원인을 수정했으므로 다시 실행해 본다.
}
return 1;
}
int main()
{
int s = 0;
__try
{
s = 10 / n ; // Code : 0xc0000094
char* p = 0;
*p = 'A'; // access - violation Code : 0xc0000005
printf( "%d\n", s );
}
// 1: 핸들러 수행, -1: 예외난곳을 다시 실행 0: 외부의 __try블록으로 전달.
__except( Filter( GetExceptionCode() ) )
{
printf( "예외발생: %x\n", GetExceptionCode() );
}
printf("프로그램은 계속 실행\n");
}
4. C++ throw의 __except
more..
// C++예외 e06d7363 를 발생시키기!!!!!!!!
int main()
{
__try
{
throw 1; // C++ 예외...
}
__except( 1 )
{
printf("예외 번호 : %x\n", GetExceptionCode() );
}
}
int main()
{
__try
{
throw 1; // C++ 예외...
}
__except( 1 )
{
printf("예외 번호 : %x\n", GetExceptionCode() );
}
}
5. STH( Structure Termination Handling ) __try, __finally ( 구조화된 종료 처리 )
1) 개념
more..
DWORD foo()
{
DWORD ret = 0;
__try
{
// 성능이 떨어질 수 있으므로 return은 자제하자.!!!
return ret; // 이순간 리턴값을 잠시 스택에 보관하고
// finally 를 실행한 후에 .. 리턴값을 다시 꺼내서 리턴.
}
__finally
{
BOOL b = AbnormalTermination();
if ( b == TRUE )
{
printf("__try를 탈출하는 코드(리턴,예외) 발생..\n");
}
else
{
printf("....\n");
}
printf( "이 부분은 try를 벗어나려고 하면 항상 호출됩니다.\n" );
}
return 0;
}
int main()
{
int s = foo();
printf( "%d\n", s );
}
{
DWORD ret = 0;
__try
{
// 성능이 떨어질 수 있으므로 return은 자제하자.!!!
return ret; // 이순간 리턴값을 잠시 스택에 보관하고
// finally 를 실행한 후에 .. 리턴값을 다시 꺼내서 리턴.
}
__finally
{
BOOL b = AbnormalTermination();
if ( b == TRUE )
{
printf("__try를 탈출하는 코드(리턴,예외) 발생..\n");
}
else
{
printf("....\n");
}
printf( "이 부분은 try를 벗어나려고 하면 항상 호출됩니다.\n" );
}
return 0;
}
int main()
{
int s = foo();
printf( "%d\n", s );
}
2) 응용 ( 자원관리를 __finally 에서 담당해준다.!!! )
more..
// STH를 사용하는 의사코드..
// One Entry Multiple Exit
BOOL foo()
{
HANDLE hFile = INVALID_HANDLE_VALUE; // -1
BOOL ret = FALSE;
char* buf = 0;
hFile = CreateFile(...);
if ( hFile == -1 ) return FALSE;
buf = new char[1000];
if ( buf == 0 ) return FALSE;
ret = ReadFile(...);
if ( ret == FALSE ) { CloseHandle( hFile ); delete[] buf;
return FALSE;
}
// 성공...
CloseHandle( hFile );
delete[] buf;
return TRUE;
}
///////////////////////////////////////////////////////////
BOOL foo()
{
HANDLE hFile = INVALID_HANDLE_VALUE; // -1
BOOL ret = FALSE;
char* buf = 0;
hFile = CreateFile(...);
if ( hFile != -1 )
{
buf = new char[1000];
if ( buf != 0 )
{
ret = ReadFile(...);
if ( ret != FALSE )
{
// 성공.....
}
delete[] buf;
}
CloseHandle( hFile );
}
return ret;
}
///////////////////////////////////////////////////////////
// 모든 자원관리를 한군데로 몰아서 한다.
// return 은 성능에 문제를 주므로 __leave 를 써서 finally로 간다.
// STH를 사용한 자원 관리 기법 - 23장(제프리)
////////////////////////////////////////////////////////
BOOL foo()
{
// 필요한 변수를 실패값으로 초기화 해서 만들어라.
HANDLE hFile = INVALID_HANDLE_VALUE; // -1
BOOL ret = FALSE;
char* buf = 0;
// __try 안에서 자원 할당과 사용을 한다.
__try
{
hFile = CreateFile(...);
if ( hFile == -1 ) __leave; // goto __finally
buf = new char[1000];
if ( buf == 0 ) __leave;
ret = ReadFile(...);
if ( ret == FALSE ) __leave;
}
__finally
{
// 이부분은 반드시 실행됨이 보장된다. 자원해지.
if ( buf != 0 ) delete[] buf;
if ( hFile != INVALID_HANDLE_VALUE ) CloseHandle( hFile );
}
return ret;
}
// One Entry Multiple Exit
BOOL foo()
{
HANDLE hFile = INVALID_HANDLE_VALUE; // -1
BOOL ret = FALSE;
char* buf = 0;
hFile = CreateFile(...);
if ( hFile == -1 ) return FALSE;
buf = new char[1000];
if ( buf == 0 ) return FALSE;
ret = ReadFile(...);
if ( ret == FALSE ) { CloseHandle( hFile ); delete[] buf;
return FALSE;
}
// 성공...
CloseHandle( hFile );
delete[] buf;
return TRUE;
}
///////////////////////////////////////////////////////////
BOOL foo()
{
HANDLE hFile = INVALID_HANDLE_VALUE; // -1
BOOL ret = FALSE;
char* buf = 0;
hFile = CreateFile(...);
if ( hFile != -1 )
{
buf = new char[1000];
if ( buf != 0 )
{
ret = ReadFile(...);
if ( ret != FALSE )
{
// 성공.....
}
delete[] buf;
}
CloseHandle( hFile );
}
return ret;
}
///////////////////////////////////////////////////////////
// 모든 자원관리를 한군데로 몰아서 한다.
// return 은 성능에 문제를 주므로 __leave 를 써서 finally로 간다.
// STH를 사용한 자원 관리 기법 - 23장(제프리)
////////////////////////////////////////////////////////
BOOL foo()
{
// 필요한 변수를 실패값으로 초기화 해서 만들어라.
HANDLE hFile = INVALID_HANDLE_VALUE; // -1
BOOL ret = FALSE;
char* buf = 0;
// __try 안에서 자원 할당과 사용을 한다.
__try
{
hFile = CreateFile(...);
if ( hFile == -1 ) __leave; // goto __finally
buf = new char[1000];
if ( buf == 0 ) __leave;
ret = ReadFile(...);
if ( ret == FALSE ) __leave;
}
__finally
{
// 이부분은 반드시 실행됨이 보장된다. 자원해지.
if ( buf != 0 ) delete[] buf;
if ( hFile != INVALID_HANDLE_VALUE ) CloseHandle( hFile );
}
return ret;
}
6. SEH 를 응용해서 메모리 할당 해보기. ( 일명 : Big Shell )
more..
struct CELL
{
char data[4096-5]; // 1Page- 5byte..
};
int main()
{
// 필요한 CELL 만큼 가상주소를 예약한다.
CELL* pTable = (CELL*)VirtualAlloc( 0, sizeof(CELL)*1000,
MEM_RESERVE, PAGE_NOACCESS );
printf( "예약된 주소 : %p\n", pTable );
while( 1 )
{
int no = 0;
char data[4096] = { 0 };
printf( "CELL 번호 >> " );
scanf( "%d", &no );
printf( "DATA >> " );
scanf( "%s", data );
/////////////////////////////////
__try
{
// 확정된 데이타에 더 작은 데이터를 넣는다면 에러가 나오지 않는다.!!
strcpy( pTable[no].data, data );
}
__except( 1 )
{
printf( "%d CELL을 확정 합니다.\n", no );
VirtualAlloc( &pTable[no], sizeof(CELL), MEM_COMMIT, PAGE_READWRITE );
// 이제 다시 복사한다.
strcpy( pTable[no].data, data );
}
}
}
{
char data[4096-5]; // 1Page- 5byte..
};
int main()
{
// 필요한 CELL 만큼 가상주소를 예약한다.
CELL* pTable = (CELL*)VirtualAlloc( 0, sizeof(CELL)*1000,
MEM_RESERVE, PAGE_NOACCESS );
printf( "예약된 주소 : %p\n", pTable );
while( 1 )
{
int no = 0;
char data[4096] = { 0 };
printf( "CELL 번호 >> " );
scanf( "%d", &no );
printf( "DATA >> " );
scanf( "%s", data );
/////////////////////////////////
__try
{
// 확정된 데이타에 더 작은 데이터를 넣는다면 에러가 나오지 않는다.!!
strcpy( pTable[no].data, data );
}
__except( 1 )
{
printf( "%d CELL을 확정 합니다.\n", no );
VirtualAlloc( &pTable[no], sizeof(CELL), MEM_COMMIT, PAGE_READWRITE );
// 이제 다시 복사한다.
strcpy( pTable[no].data, data );
}
}
}
7. API Hooking ( SetTimer를 바꿔치기 해보자 - 미완성 ㅜ_ㅜ )
1) DLL ( Inject 할 Dll )
more..
////////////////////////////////////////////////////////////////////////////////
// SpeedHook.dll 만들기
////////////////////////////////////////////////////////////////////////////////
#include <dbghelp.h>
#pragma comment( lib, "dbghelp.lib" )
typedef UINT_PTR (WINAPI* F)( HWND, UINT_PTR, UINT, TIMERPROC ); void Replace( HMODULE hDll, // exe의 주소
char* name, // 후킹할 함수를 가진 dll의 이름
PROC oldfunc, // 원래 API함수의 주소
PROC newfunc ) // 후킹할 함수
{
// .exe에서 .idata section의 주소를 얻는다.
ULONG sz;
IMAGE_IMPORT_DESCRIPTOR* pImage = (IMAGE_IMPORT_DESCRIPTOR*)
ImageDirectoryEntryToData( hDll, // 모듈 주소
TRUE, // Mapping?
IMAGE_DIRECTORY_ENTRY_IMPORT,
&sz );
// 2. User32.dll 의 항목을 구한다.
for( ; pImage->Name; ++pImage )
{
char* p = (char*)hDll + pImage->Name;
if( strcmpi( p, name ) == 0 ) break; //찾은경우
}
if ( pImage->Name == 0 )
{
return;
}
// 3. Thunk Table에서 원하는 함수를 찾는다.
IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)
( (char*)hDll + pImage->FirstThunk );
// 4. 이제 함수를 찾아서 새로운 함수 주소를 덮어 쓴다.
for ( ; pThunk->u1.Function; ++pThunk )
{
if( (PROC)(pThunk->u1.Function) == oldfunc )
{
PROC* p = (PROC*)&(pThunk->u1.Function);
DWORD old;
VirtualProtect( p, sizeof(PROC), PAGE_READWRITE, &old );
WriteProcessMemory( GetCurrentProcess(), p, &newfunc, sizeof(PROC), 0 );
}
}
}
UINT_PTR MyTimer( HWND hwnd, UINT_PTR id, UINT ms, TIMERPROC f )
{
HMODULE h = GetModuleHandle( "user32.dll" );
F func = (F)GetProcAddress( h, "SetTimer" );
// 원래 함수를 호출한다.
return func( hwnd, id, ms/10, f );
}
void Setup()
{
Replace( GetModuleHandle(0), "user32.dll", (PROC)SetTimer, (PROC)MyTimer );
}
BOOL WINAPI DllMain( HANDLE h, DWORD r, LPVOID how )
{
if ( r == DLL_PROCESS_ATTACH )
{
Setup();
}
return TRUE;
}
// SpeedHook.dll 만들기
////////////////////////////////////////////////////////////////////////////////
#include <dbghelp.h>
#pragma comment( lib, "dbghelp.lib" )
typedef UINT_PTR (WINAPI* F)( HWND, UINT_PTR, UINT, TIMERPROC ); void Replace( HMODULE hDll, // exe의 주소
char* name, // 후킹할 함수를 가진 dll의 이름
PROC oldfunc, // 원래 API함수의 주소
PROC newfunc ) // 후킹할 함수
{
// .exe에서 .idata section의 주소를 얻는다.
ULONG sz;
IMAGE_IMPORT_DESCRIPTOR* pImage = (IMAGE_IMPORT_DESCRIPTOR*)
ImageDirectoryEntryToData( hDll, // 모듈 주소
TRUE, // Mapping?
IMAGE_DIRECTORY_ENTRY_IMPORT,
&sz );
// 2. User32.dll 의 항목을 구한다.
for( ; pImage->Name; ++pImage )
{
char* p = (char*)hDll + pImage->Name;
if( strcmpi( p, name ) == 0 ) break; //찾은경우
}
if ( pImage->Name == 0 )
{
return;
}
// 3. Thunk Table에서 원하는 함수를 찾는다.
IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)
( (char*)hDll + pImage->FirstThunk );
// 4. 이제 함수를 찾아서 새로운 함수 주소를 덮어 쓴다.
for ( ; pThunk->u1.Function; ++pThunk )
{
if( (PROC)(pThunk->u1.Function) == oldfunc )
{
PROC* p = (PROC*)&(pThunk->u1.Function);
DWORD old;
VirtualProtect( p, sizeof(PROC), PAGE_READWRITE, &old );
WriteProcessMemory( GetCurrentProcess(), p, &newfunc, sizeof(PROC), 0 );
}
}
}
UINT_PTR MyTimer( HWND hwnd, UINT_PTR id, UINT ms, TIMERPROC f )
{
HMODULE h = GetModuleHandle( "user32.dll" );
F func = (F)GetProcAddress( h, "SetTimer" );
// 원래 함수를 호출한다.
return func( hwnd, id, ms/10, f );
}
void Setup()
{
Replace( GetModuleHandle(0), "user32.dll", (PROC)SetTimer, (PROC)MyTimer );
}
BOOL WINAPI DllMain( HANDLE h, DWORD r, LPVOID how )
{
if ( r == DLL_PROCESS_ATTACH )
{
Setup();
}
return TRUE;
}
2) Inject ( DLL을 Inject 하기.. )
more..
void DLLInject( DWORD pid, const char* path )
{
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | // 프로세스의 정보 요청
PROCESS_CREATE_THREAD | // CreateRemoteThread를 사용하기 위해
PROCESS_VM_OPERATION | // VirtualAllocEx/VirtualFreeEx를 사용하기 위해
PROCESS_VM_WRITE,
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);
WaitForSingleObject( hThread, INFINITE );
CloseHandle( hThread );
VirtualFreeEx( hProcess, p, sizeof(path), MEM_RELEASE );
// 대상 프로세스에서 ".dll"을 unload 한다
// (CreateRemoteThread와 FreeLibrary를 이용하여)
hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)GetProcAddress( hDll,
"FreeLibrary" ),
(void*)p, 0, NULL );
WaitForSingleObject( hThread, INFINITE );
// Clean up
CloseHandle( hThread );
}
int main()
{
HWND hwnd = FindWindow( 0, "지뢰 찾기");
if ( hwnd == 0 )
{
printf("계산기 부터 실행하세요..\n");
return 0;
}
// 계산기 프로세스에 DLL을 강제로 넣는다.
DWORD pid;
DWORD tid = GetWindowThreadProcessId( hwnd, &pid );
DLLInject( pid, "C:\\SpeedHook.dll");
getch();
}
{
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | // 프로세스의 정보 요청
PROCESS_CREATE_THREAD | // CreateRemoteThread를 사용하기 위해
PROCESS_VM_OPERATION | // VirtualAllocEx/VirtualFreeEx를 사용하기 위해
PROCESS_VM_WRITE,
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);
WaitForSingleObject( hThread, INFINITE );
CloseHandle( hThread );
VirtualFreeEx( hProcess, p, sizeof(path), MEM_RELEASE );
// 대상 프로세스에서 ".dll"을 unload 한다
// (CreateRemoteThread와 FreeLibrary를 이용하여)
hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)GetProcAddress( hDll,
"FreeLibrary" ),
(void*)p, 0, NULL );
WaitForSingleObject( hThread, INFINITE );
// Clean up
CloseHandle( hThread );
}
int main()
{
HWND hwnd = FindWindow( 0, "지뢰 찾기");
if ( hwnd == 0 )
{
printf("계산기 부터 실행하세요..\n");
return 0;
}
// 계산기 프로세스에 DLL을 강제로 넣는다.
DWORD pid;
DWORD tid = GetWindowThreadProcessId( hwnd, &pid );
DLLInject( pid, "C:\\SpeedHook.dll");
getch();
}