• WriteFile() API 钩取


    #include "windows.h"
    #include "stdio.h"
    
    LPVOID g_pfWriteFile = NULL;
    CREATE_PROCESS_DEBUG_INFO g_cpdi;
    BYTE g_chINT3 = 0xCC, g_chOrgByte = 0;
    
    BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde)
    {
    	// 获取 WriteFile() API 地址
    	g_pfWriteFile = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");
    
    	// API Hook - WriteFile()
    	//   更改第一个字节为0xCC(INT3)
    	//   (orginal byte是g_ch0rgByte备份)
    	memcpy(&g_cpdi, &pde->u.CreateProcessInfo, sizeof(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;
    	PEXCEPTION_RECORD per = &pde->u.Exception.ExceptionRecord;
    
    	// BreakPoint exception (INT 3) 
    	if (EXCEPTION_BREAKPOINT == per->ExceptionCode)
    	{
    		// 断点地址为 WriteFile() 地址时
    		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. 获取 WriteFile() 的 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);
    
    			// #4. 分配临时缓冲区
    			lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite + 1);
    			memset(lpBuffer, 0, dwNumOfBytesToWrite + 1);
    
    			// #5. 复制WriteFile()缓冲区到临时缓冲区 
    			ReadProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
    				lpBuffer, dwNumOfBytesToWrite, NULL);
    			printf("
    ### original string ###
    %s
    ", lpBuffer);
    
    			// #6. 将小写字母转换为大写字母
    			for (i = 0; i < dwNumOfBytesToWrite; i++)
    			{
    				if (0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A)
    					lpBuffer[i] -= 0x20;
    			}
    
    			printf("
    ### converted string ###
    %s
    ", lpBuffer);
    
    			// #7. 将变换后的缓冲区复制到WriteFile()缓冲区
    			WriteProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer,
    				lpBuffer, dwNumOfBytesToWrite, NULL);
    
    			// #8. 释放临时缓冲区
    			free(lpBuffer);
    
    			// #9.将线程上下文的EIP更改为WriteFile()首地址
    			//   (当前为 WriteFile() + 1 位置,INT3命令之后)
    			ctx.Eip = (DWORD)g_pfWriteFile;
    			SetThreadContext(g_cpdi.hThread, &ctx);
    
    			// #10. 运行被调试进程
    			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;
    }
    
    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;
    
    	if (argc != 2)
    	{
    		printf("
    USAGE : hookdbg.exe <pid>
    ");
    		return 1;
    	}
    
    	// Attach Process
    	dwPID = atoi(argv[1]);
    	if (!DebugActiveProcess(dwPID))
    	{
    		printf("DebugActiveProcess(%d) failed!!!
    "
    			"Error Code = %d
    ", dwPID, GetLastError());
    		return 1;
    	}
    
    	// 调试器循环
    	DebugLoop();
    
    	return 0;
    }
    

      这篇博客很全面:https://www.cnblogs.com/UnGeek/p/3515995.html

    DebugActiveProcess   
    说明:此函数允许将调试器捆绑到一个正在运行的进程上。
    语法:BOOL DebugActiveProcess(DWORD dwProcessId )
    参数:
    dwProcessId         DWORD  欲捆绑进程的进程标识符
    返回值                  BOOL  如果函数成功,则返回非零值;如果失败,则返回零
     
    在DebugLoop()中:
      
    WaitForDebugEvent
    说明:此函数用来等待被调试进程发生调试事件。
    语法:BOOL WaitForDebugEvent(LPDEBUG_ENENT lpDebugEventDWORD dwMilliseconds)
    参数:
    lpDebugEvent        LPDEBUG_ENENT  指向接收调试事件信息的DEBUG_ ENENT结构的指针
    dwMilliseconds      DWORD  该函数用来等待调试事件发生的毫秒数,如果这段时间内没有调试事件发生,函数将返回调用者;如果将该参数指定为INFINITE,函数将一直等待直到调试事件发生
    返回值                  BOOL:如果函数成功,则返回非零值;如果失败,则返回零
     
    ContinueDebugEvent函数
    说明:此函数允许调试器恢复先前由于调试事件而挂起的线程。
    语法:BOOL ContinueDebugEvent(DWORD dwProcessId,DWORD dwThreadIdDWORD dwContinueStatus )
    参数:
    dwProcessId         DWORD  被调试进程的进程标识符
    dwThreadId           DWORD  欲恢复线程的线程标识符
    dwContinueStatus  DWORD  此值指定了该线程将以何种方式继续,包含两个定义值DBG_CONTINUE和DBG_EXCEPTION_NOT_HANDLED
    返回值                  BOOL  如果函数成功,则返回非零值;如果失败,则返回零
     

    OnCreateProcessDebugEvent函数:  

       void *memcpy(void *to, const void *from, size_t count)

      函数memcpy()从from指向的数组向to指向的数组复制count个字符。

    OnExceptionDebugEvent函数:  

      typedef struct _EXCEPTION_RECORD {
      DWORD ExceptionCode;
      DWORD ExceptionFlags;
      struct _EXCEPTION_RECORD *ExceptionRecord;
      PVOID ExceptionAddress;
      DWORD NumberParameters;
      ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
      } EXCEPTION_RECORD;

  • 相关阅读:
    Get code into Bitbucket fast using Atlassian's SourceTree or the command line
    Django+angularJs
    修改默认python版本
    重拾python mac1.9.2
    REST
    Parameters.Add Parameters.Addrange
    sql建表前删除存在的同名表
    C#1.0
    [转]C#究竟能给开发者带来什么
    Laravel中上传图片至七牛云
  • 原文地址:https://www.cnblogs.com/whitehawk/p/11166557.html
Copyright © 2020-2023  润新知