- [필수 1] Hooking의 정의, 개념 등을 이해합니다. (Link 1)
- [필수 2] 모든 프로세스를 열거합니다. (콘솔 프로그램도 무관. Link 2, 3)
- [필수 3] 지정한 프로세스의 메모리에서 특정 주소의 데이터를 읽거나 원하는 데이터를 덮어씁니다. (Link 4, 5, 6)
- [선택 1] 직접 작성한 프로그램의 실행 흐름을 런타임 API Hooking을 이용하여 바꿔봅니다.
- [선택 2] Hooking 여부를 탐지할 수 있는 방법들을 생각하고 직접 구현해봅니다.
Link 1 - en.wikipedia.org/wiki/Hooking
Link 2 - 모든 프로세스 ID 열거 (PSAPI 사용):
docs.microsoft.com/en-us/windows/win32/psapi/enumerating-all-processes
Link 3 - 모든 프로세스 정보 열거 (Tlhel32 사용):
docs.microsoft.com/en-us/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes
Link 4 - Process ID로 Process Handle 얻기:
docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
Link 5 - 지정된 프로세스 및 주소로부터 지정된 크기만큼 데이터 읽기:
docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-readprocessmemory
Link 6 - 지정된 프로세스 및 주소에 지정된 크기 만큼 데이터 쓰기:
docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory
[필수1] Hooking의 정의 및 개념
후킹(Hooking)
리버싱에서 후킹은 정보를 가로채며, 실행 흐름을 변경하고 기존의 프로그램과는 다른 기능을 제공하는 기술.
후크(Hook)
후킹 시에 영향을 끼친 함수, 이벤트, 메세지를 처리하는 코드
[필수 2-1] 모든 프로세스를 ID 열거 (PSAPI 사용)
EnumProcesses 함수를 사용하여 각 프로세스 개체에 대한 프로세스 식별자(ID)를 검색하는 코드 및 결과
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <psapi.h>
// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS
// and compile with -DPSAPI_VERSION=1
void PrintProcessNameAndID( DWORD processID )
{
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
// Get a handle to the process.
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, processID );
// Get the process name.
if (NULL != hProcess )
{
HMODULE hMod;
DWORD cbNeeded;
if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod),
&cbNeeded) )
{
GetModuleBaseName( hProcess, hMod, szProcessName,
sizeof(szProcessName)/sizeof(TCHAR) );
}
}
// Print the process name and identifier.
_tprintf( TEXT("%s (PID: %u)\n"), szProcessName, processID );
// Release the handle to the process.
CloseHandle( hProcess );
}
int main( void )
{
// Get the list of process identifiers.
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
{
return 1;
}
// Calculate how many process identifiers were returned.
cProcesses = cbNeeded / sizeof(DWORD);
// Print the name and process identifier for each process.
for ( i = 0; i < cProcesses; i++ )
{
if( aProcesses[i] != 0 )
{
PrintProcessNameAndID( aProcesses[i] );
}
}
return 0;
}
[필수2-1] 결과
A - EnumProcesses 함수를 사용하여 프로세스 목록을 가져온다.
B - 각 프로세스에 대해 main함수는 PrintProcesessNameAndID 함수를 호출하여 프로세스 식별자를 전달한다.
C - PrintProcesessNameAndID는 차례로 OpenProcess 함수를 호출하여 프로세스 핸들을 얻는다.
D - PrintProcesessNameAndID는 EnumProcessModules 함수를 호출하여 모듈핸들을 얻는다.
F - PrintProcesessNameAndID는 GetModuleBaseName 함수를 호출하여 실행파일의 이름을 얻고 프로세스 식별자와 함께 이름이 표시된다.
[필수2-2] 모든 프로세스 정보 열거 (Tlhel32 사용)
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
// Forward declarations:
BOOL GetProcessList( );
BOOL ListProcessModules( DWORD dwPID );
BOOL ListProcessThreads( DWORD dwOwnerPID );
void printError( TCHAR* msg );
int main( void )
{
GetProcessList( );
return 0;
}
BOOL GetProcessList( )
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
printError( TEXT("CreateToolhelp32Snapshot (of processes)") );
return( FALSE );
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first process,
// and exit if unsuccessful
if( !Process32First( hProcessSnap, &pe32 ) )
{
printError( TEXT("Process32First") ); // show cause of failure
CloseHandle( hProcessSnap ); // clean the snapshot object
return( FALSE );
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
_tprintf( TEXT("\n\n=====================================================" ));
_tprintf( TEXT("\nPROCESS NAME: %s"), pe32.szExeFile );
_tprintf( TEXT("\n-------------------------------------------------------" ));
// Retrieve the priority class.
dwPriorityClass = 0;
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
if( hProcess == NULL )
printError( TEXT("OpenProcess") );
else
{
dwPriorityClass = GetPriorityClass( hProcess );
if( !dwPriorityClass )
printError( TEXT("GetPriorityClass") );
CloseHandle( hProcess );
}
_tprintf( TEXT("\n Process ID = 0x%08X"), pe32.th32ProcessID );
_tprintf( TEXT("\n Thread count = %d"), pe32.cntThreads );
_tprintf( TEXT("\n Parent process ID = 0x%08X"), pe32.th32ParentProcessID );
_tprintf( TEXT("\n Priority base = %d"), pe32.pcPriClassBase );
if( dwPriorityClass )
_tprintf( TEXT("\n Priority class = %d"), dwPriorityClass );
// List the modules and threads associated with this process
ListProcessModules( pe32.th32ProcessID );
ListProcessThreads( pe32.th32ProcessID );
} while( Process32Next( hProcessSnap, &pe32 ) );
CloseHandle( hProcessSnap );
return( TRUE );
}
BOOL ListProcessModules( DWORD dwPID )
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
printError( TEXT("CreateToolhelp32Snapshot (of modules)") );
return( FALSE );
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
printError( TEXT("Module32First") ); // show cause of failure
CloseHandle( hModuleSnap ); // clean the snapshot object
return( FALSE );
}
// Now walk the module list of the process,
// and display information about each module
do
{
_tprintf( TEXT("\n\n MODULE NAME: %s"), me32.szModule );
_tprintf( TEXT("\n Executable = %s"), me32.szExePath );
_tprintf( TEXT("\n Process ID = 0x%08X"), me32.th32ProcessID );
_tprintf( TEXT("\n Ref count (g) = 0x%04X"), me32.GlblcntUsage );
_tprintf( TEXT("\n Ref count (p) = 0x%04X"), me32.ProccntUsage );
_tprintf( TEXT("\n Base address = 0x%08X"), (DWORD) me32.modBaseAddr );
_tprintf( TEXT("\n Base size = %d"), me32.modBaseSize );
} while( Module32Next( hModuleSnap, &me32 ) );
CloseHandle( hModuleSnap );
return( TRUE );
}
BOOL ListProcessThreads( DWORD dwOwnerPID )
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( hThreadSnap == INVALID_HANDLE_VALUE )
return( FALSE );
// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32);
// Retrieve information about the first thread,
// and exit if unsuccessful
if( !Thread32First( hThreadSnap, &te32 ) )
{
printError( TEXT("Thread32First") ); // show cause of failure
CloseHandle( hThreadSnap ); // clean the snapshot object
return( FALSE );
}
// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if( te32.th32OwnerProcessID == dwOwnerPID )
{
_tprintf( TEXT("\n\n THREAD ID = 0x%08X"), te32.th32ThreadID );
_tprintf( TEXT("\n Base priority = %d"), te32.tpBasePri );
_tprintf( TEXT("\n Delta priority = %d"), te32.tpDeltaPri );
_tprintf( TEXT("\n"));
}
} while( Thread32Next(hThreadSnap, &te32 ) );
CloseHandle( hThreadSnap );
return( TRUE );
}
void printError( TCHAR* msg )
{
DWORD eNum;
TCHAR sysMsg[256];
TCHAR* p;
eNum = GetLastError( );
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL );
// Trim the end of the line and terminate it with a null
p = sysMsg;
while( ( *p > 31 ) || ( *p == 9 ) )
++p;
do { *p-- = 0; } while( ( p >= sysMsg ) &&
( ( *p == '.' ) || ( *p < 33 ) ) );
// Display the message
_tprintf( TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
}
[필수2-2] 결과
A - GetProcessList 함수는 CreateToolhelp32Snapshot을 사용하여 시스템에서 현재 실행중인 프로세스의 스냅 샷을 만든 다음 Process32First 및 Process32Next를 사용하여 스냅 샷에 기록된 목록을 살펴본다.
B - 차례대로 각 프로세스에 대해 모듈목록탐색에 설명 도니 함수와 스레드 목록탐색에 설명된 함수를 GetProcessList로 함수로 호출한다.
C -printError은 일반적으로 보안 제한으로 인해 발생하는 오류의 원인을 표시한다.
[필수 3] 지정한 프로세스의 메모리에서 특정 주소의 데이터를 읽거나 원하는 데이터를 덮어쓴다.
OpenProcess function - 기존 로컬 프로세스 개체를 열어주는 함수
ReadProcessMemory function - 프로세스 메로리를 읽는 함수
WriteProcessMemory function - 지정된 프로세스의 메모리 영역에 데이터를 쓰는 함수
현재 사용중인 카카오톡 PID 11224. 위의 함수를 이용하여 [필수3]과제를 해보겠습니다.
#include <stdio.h>
#include <windows.h>
int main() {
HANDLE num;
if ((num = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 11224)) == NULL)
printf("Error\n\n");
else
printf("Handle: %d\n\n");
return 0;
}
#include <stdio.h>
#include <windows.h>
#include <memoryapi.h>
int main() {
HANDLE num;
if ((num = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 11224)) == NULL)
printf("Error\n\n");
else
printf("Handle: %d\n\n",num);
DWORD buf = 0;
if (ReadProcessMemory(num, (LPVOID)0xA70000, &buf, sizeof(DWORD), NULL) != 0)
{
buf++;
WriteProcessMemory(num, (LPVOID)0xA70000, (LPCVOID)&buf, sizeof(DWORD), NULL);
}
return 0;
}
[필수3] 결과 값
'리버싱 > 리버싱 걸음마' 카테고리의 다른 글
정보보안 SUA - [정보보안공부] 7주차 과제 - DLL Injection 수행 (0) | 2021.03.17 |
---|---|
정보보안 SUA - [정보보안공부] 6주차 과제 - 런타임 API Hooking 수행 (0) | 2021.03.11 |
정보보안 SUA - [정보보안공부] 4주차 과제 - Windows 데스크톱 앱 개발 (0) | 2021.02.26 |
정보보안 SUA - [정보보안공부] 3주차 과제 - 리버싱 로드 맵 및 PE로더 (0) | 2021.02.24 |
정보보안 SUA - [정보보안공부] 2주차 과제 - Windows 데스크톱 앱 개C/C++ 언어의 다양한 개념들이 x86 어셈블리 언어로 변환 결과물 (0) | 2021.02.05 |