#include <windows.h>
#include <stdio.h>
LPVOID g_pfWriteFile = NULL;
CREATE_PROCESS_DEBUG_INFO g_cpdi;
BYTE g_chINT3 = 0xCC, g_chOrgByte = 0;
HWND g_hWnd;
//Define the local function
void DebugLoop(void);
BOOL OnCreateProcessDebugEvent (LPDEBUG_EVENT pde);
BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pde);
int main(int argc, char* argv[])
{
DWORD dwPID;
if( argc != 2 )
{
printf("\nUSAGE : hookdbg.exe <pid>\n");
// return 1;
}
// Attach Process
ShellExecute(NULL, "open", "C:\\Api후킹대상파일.exe", NULL, NULL, SW_SHOWNORMAL);
Sleep(1000);
if(argv[1] == NULL)
{
g_hWnd = FindWindow(NULL, "제목없음 - _________");
if(g_hWnd == NULL)
{
MessageBox(NULL, "찾기실패", "대상 파일을 찾을 수 없습니다.", MB_OK);
return 1;
}
GetWindowThreadProcessId(g_hWnd, &dwPID);
}
else
{
dwPID = atoi(argv[1]);
}
if(!DebugActiveProcess(dwPID))
{
printf( "DebugActiveProcess(%d) failed!!! \n"
"Error Code = %d\n", dwPID, GetLastError());
return 1;
}
//Debuger loop
DebugLoop();
return 0;
}
void DebugLoop()
{
DEBUG_EVENT de;
DWORD dwContinueStatus;
//Wait for event signal Create for Debuggee
while(WaitForDebugEvent(&de, INFINITE) )
{
dwContinueStatus = DBG_CONTINUE;
//Debuggee process create or attach event
if( CREATE_PROCESS_DEBUG_EVENT == de.dwDebugEventCode )
{
OnCreateProcessDebugEvent(&de);
}
//Exception event
else if( EXCEPTION_DEBUG_EVENT == de.dwDebugEventCode )
{
if( OnExceptionDebugEvent(&de) )
continue;
}
//Debuggee process exit event
else if( EXIT_PROCESS_DEBUG_EVENT == de.dwDebugEventCode )
{
// Debuggee exit -> Debugger exit
break;
}
// Debuggee's resume
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);
}
}
BOOL OnCreateProcessDebugEvent (LPDEBUG_EVENT pde)
{
// Get the address of WriteFile() API
g_pfWriteFile = GetProcAddress(GetModuleHandle("gdi32.dll"),
"TextOutA");
//API Hook - WriteFile()
//첫번째 byte를 0xCC (INT3)로 변경
//(orginal byte는 백업 - g_chOrgByte)
g_cpdi = pde->u.CreateProcessInfo; // CREATE_PROCESS_DEBUG_INFO
ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chOrgByte, sizeof(BYTE), NULL);
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chINT3, sizeof(BYTE), NULL);
return TRUE;
}
BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pde)
{
CONTEXT ctx;
PBYTE lpBuffer = NULL;
DWORD dwNumOfBytesToWrite, dwAddrOfBuffer, i;
INT nX, nY, nStrlen;
LPVOID lpString;
PEXCEPTION_RECORD per = &pde->u.Exception.ExceptionRecord;
char szTaeho1[256];
char szTaeho2[256];
//BreakPoint exception (INT 3)인 경우
if( EXCEPTION_BREAKPOINT == per->ExceptionCode)
{
//BP주소가 WriteFile() API 주소인 경우
if( g_pfWriteFile == per->ExceptionAddress)
{
//#1. Unhook
//0xCC로 덮어쓴 부분을 original byte로 되돌림
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chOrgByte, sizeof(BYTE), NULL);
//#2. Thread Context 구하기
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(g_cpdi.hThread, &ctx);
//#3. WriteFiel()의 param 2, 3값 구하기
// 함수의 파라미터는 해당 프로세스의 스택에 존재함
// param 2 : ESP + 0x8
// param 3 : ESP + 0xC
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0x8),
&dwAddrOfBuffer, sizeof(DWORD), NULL);
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0xC),
&dwNumOfBytesToWrite, sizeof(DWORD), NULL);
{
//TextOut의 X좌표
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)( ctx.Esp + sizeof(HDC) + 0x4 ),
(int*)&nX, sizeof(INT), NULL);
//TextOut의 Y좌표
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)( ctx.Esp + sizeof(HDC) + 0x8 ),
(int*)&nY, sizeof(INT), NULL);
//TextOut의 문자열 버퍼 주소를 구함
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)( ctx.Esp + sizeof(HDC) + 0x8 + sizeof(LPVOID) ),
&lpString, sizeof(LPVOID), NULL);
//TextOut의 문자열 길이를 구함.
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)( ctx.Esp + sizeof(HDC) + 0x8 + sizeof( LPCTSTR) + sizeof(INT) ),
(int*)&nStrlen, sizeof(INT), NULL);
//TextOut의 문자열 버퍼 주소에 있는 문자열을 문자열의 길이만큼 긁어 옴.
ReadProcessMemory(g_cpdi.hProcess, lpString,
szTaeho1, nStrlen, NULL);
szTaeho1[nStrlen] = NULL;
// printf("\nlpString = %x \n", lpString);
// printf("x=%d, y=%d,\tLength= %d\n", nX, nY, nStrlen);
if(lstrcmp(szTaeho1, "갑오") == 0)
{
printf("\n+_+ TextOutMsg : %s\n", szTaeho1);
}
}
//#4. 임시 버퍼 할당
lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite + 1);
memset(lpBuffer, 0, dwNumOfBytesToWrite + 1);
//#5. WriteFile()의 버퍼를 임시 버퍼에 복사
ReadProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
lpBuffer, dwNumOfBytesToWrite, NULL);
// printf("\n+_+ original string : %s\n", lpBuffer);
//#6. 소문자 -> 대문자 변환
for( i = 0; i < dwNumOfBytesToWrite; i++)
{
if(0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A )
lpBuffer[i] -= 0x20;
}
// printf("\n+_+ Converted string : %s\n", lpBuffer);
//#7. 변환된 버퍼를 WriteFile() 버퍼로 복사
WriteProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
lpBuffer, dwNumOfBytesToWrite, NULL);
//#8. 임시 버퍼 해제
free(lpBuffer);
//#9. Thread Context의 EIP를 WriteFile() 시작으로 변경
// (현재는 WriteFile() + 1 위치 <- INT3 명령 이후)
ctx.Eip = (DWORD) g_pfWriteFile;
SetThreadContext(g_cpdi.hThread, &ctx);
//#10. Debuggee 프로세스를 진행시킴
ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);
Sleep(0);
//#11. API Hook
WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,
&g_chINT3, sizeof(BYTE), NULL);
return TRUE;
}
}
return FALSE;
}