目录

API勾取

调试钩取

流程如下:

  1. 对想钩取的进程进行附加操作,使之成为被调试者
  2. 钩子:将API起始地址的第一个字节修改为0xCC
  3. 调用相应API时,控制权转移到调试器
  4. 执行需要的操作(操作参数、返回值等)
  5. 脱钩:将0xCC恢复为原来的值(正常运行API)
  6. 运行相应API(无0xCC的正常状态)
  7. 钩子:再次修改为0xCC(为了继续钩取)
  8. 控制权返还给被调试者
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# include "windows.h"  
# include "stdio.h"  
  
LPVOID g_pfWriteFile = NULL;  
CREATE_PROCESS_DEBUG_INFO g_cpdi;  
BYTE g_chINT3 = 0xCC;  
BYTE g_ch0rgByte = 0;  
  
BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde)  
{  
	// 获取WriteFile() API的地址  
	g_pfWriteFile = GetProcAddress(GetModuleHandle("kernel32.dll"), "WriteFile");  
	printf("g_pfWriteFile:%d\n", g_pfWriteFile);  
	// API钩子 WriteFile()  
	memcpy(&g_cpdi, &pde->u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_EVENT));  
	ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile,  
		&g_ch0rgByte, 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;  
	PEXCEPTION_RECORD per = &pde->u.Exception.ExceptionRecord;  
  
	if (EXCEPTION_BREAKPOINT == per->ExceptionCode)  
	{  
		if (g_pfWriteFile == per->ExceptionAddress)  
		{  
			// 将0xcc恢复为original byte  
			WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile,  
				&g_ch0rgByte, sizeof(BYTE), NULL);  
  
			// 获取线程上下文  
			ctx.ContextFlags = CONTEXT_CONTROL;  
			GetThreadContext(g_cpdi.hThread, &ctx);  
  
			// 获取WriteFile的第2,3个参数  
			ReadProcessMemory(g_cpdi.hProcess, (LPCVOID)(ctx.Esp + 8),  
				&dwAddrOfBuffer, sizeof(DWORD), NULL);  
			ReadProcessMemory(g_cpdi.hProcess, (LPCVOID)(ctx.Esp + 0xc),  
				&dwNumOfBytesToWrite, sizeof(DWORD), NULL);  
			  
			/*dwAddrOfBuffer = ctx.Rsi;  
			dwNumOfBytesToWrite = ctx.Rdx;*/  
  
			printf("size: %d\n", dwNumOfBytesToWrite);  
  
			// 分配临时缓冲区  
			lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite + 1);  
			memset(lpBuffer, 0, dwNumOfBytesToWrite + 1);  
  
			// 复制WriteFile缓冲区到临时缓冲区  
			ReadProcessMemory(g_cpdi.hProcess, (LPCVOID)dwAddrOfBuffer,  
				lpBuffer, dwNumOfBytesToWrite, NULL);  
			printf("\n original string: %s\n", lpBuffer);  
  
			// 小写字母转大写字母  
			for (i = 0; i < dwNumOfBytesToWrite; i++)  
			{  
				if (0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A)  
				{  
					lpBuffer[i] = lpBuffer[i] - 0x20;  
				}  
			}  
  
			printf("\n converted string: %s\n", lpBuffer);  
  
			// 将变换后的缓冲区换到WriteFile中  
			WriteProcessMemory(g_cpdi.hThread, (LPVOID)dwAddrOfBuffer,  
				lpBuffer, dwNumOfBytesToWrite, NULL);  
  
			free(lpBuffer);  
  
			// 将线程上下文的EIP更改为WriteFile的首地址  
			ctx.Eip = (DWORD)g_pfWriteFile;  
			SetThreadContext(g_cpdi.hThread, &ctx);  
			ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);  
			Sleep(0);  
  
			WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile, &g_chINT3,  
				sizeof(BYTE), NULL);  
			return TRUE;  
		}  
	}  
	return FALSE;  
}  
  
void DebugLoop()  
{  
	DEBUG_EVENT de;  
	DWORD dwContinueStatus;  
	while (WaitForDebugEvent(&de, INFINITE))  
	{  
		dwContinueStatus = DBG_CONTINUE;  
		// 被调试进程生成或附加  
		if (CREATE_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)  
			OnCreateProcessDebugEvent(&de);  
		// 异常  
		else if (EXCEPTION_DEBUG_EVENT == de.dwDebugEventCode)  
		{  
			if (OnExceptionDebugEvent(&de))  
				continue;  
		}  
		// 中止  
		else if (EXIT_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)  
			break;  
		ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);  
	}  
}  
  
int main(int argc, char* argv[])  
{  
	DWORD dwPID;  
	dwPID = atoi(argv[1]);  
  
	// 使调试器附加到一个活动进程并且调试它  
	if (!DebugActiveProcess(dwPID))  
	{  
		printf("DebugActiveProcess failed\n");  
		return 1;  
	}  
	DebugLoop();  
	return 0;  
}