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("\n### original string ###\n%s\n", lpBuffer);

			// #6. 将小写字母转换为大写字母
			for (i = 0; i < dwNumOfBytesToWrite; i++)
			{
				if (0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A)
					lpBuffer[i] -= 0x20;
			}

			printf("\n### converted string ###\n%s\n", 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("\nUSAGE : hookdbg.exe <pid>\n");
		return 1;
	}

	// Attach Process
	dwPID = atoi(argv[1]);
	if (!DebugActiveProcess(dwPID))
	{
		printf("DebugActiveProcess(%d) failed!!!\n"
			"Error Code = %d\n", 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;

原文地址:https://www.cnblogs.com/whitehawk/p/11166557.html

时间: 2024-08-05 07:51:12

WriteFile() API 钩取的相关文章

c#使用easyhook库进行API钩取

目标:使calc程序输入的数自动加1 (当别人使用时,总会得不到正确的结果,哈哈) 编写注入程序 ————————————————————————————————— class Program中的方法,注入dll到目标进程 ——————————————————————-—————————— static String ChannelName = null; static void Main(string[] args) { Int32.TryParse(args[0], out TargetPI

钩取API之代码修改方法【一】

IAT方式就不去花精力了,加了壳的程序用这方法压根用不上. 就熟悉一下代码修改方法.书上用的是隐藏进程的实例 第一种办法 一,枚举进程,给所有进程加载DLL[用远程线程注入] 二,传入需要隐藏的进程名 三,判断有没有修改过需要钩取的函数,如果还没有修改过就改掉,跳向自己的函数,同时保存好原来的值 四,在自己的替代函数里将原来的值修改回去,并再执行一次,执行完做相关处理 五,在自己的替代函数最后再钩取函数,修改跳转到替代函数 基本逻辑就是这样,像是移花接木啊... DLL代码: #define S

钩取API之调试器模式

描述:当代码调试遇到INT3指令就会中断运行EXCEPTION_BREAKPOINT异常事件会被传送到调试器,此时控制权就到了调试器了,利用这种特性钩取API. 流程:将要钩取的API的起始部分修改为0xCC(INT3),控制权移到调试器后执行想实现的代码后,再修改回去重新进入运行状态. LPVOID g_pfWriteFile = NULL;CREATE_PROCESS_DEBUG_INFO g_cpdi;BYTE g_chINT3 = 0xCC, g_chOrgByte = 0; int _

百度音乐API抓取

百度音乐API抓取 前段时间做了一个本地音乐的播放器 github地址,想实现在线播放的功能,于是到处寻找API,很遗憾,不是歌曲不全就是质量不高.在网上发现这么一个APIMRASONG博客,有“获取榜单,搜索歌词,下载地址,专辑”信息等等接口. 后来发现有些接口使用起来不是很方便,比如获取专辑信息,只能得到歌曲列表的id信息,所以自己决定用fiddler来对百度音乐安卓客户端抓包. 下面是一系列的接口: 一. 关键词建议: GET: http://tingapi.ting.baidu.com/

和风api爬取天气预报数据

''' 和风api爬取天气预报数据 目标:https://free-api.heweather.net/s6/weather/forecast?key=cc33b9a52d6e48de852477798980b76e&location=CN101090101 得到中国城市的代码:https://a.hecdn.net/download/dev/china-city-list.csv 目前先查20个城市第二天的天气 ''' import requests url = "https://a.

钩取API应用实例【NtCreateFile】

#include "stdafx.h"#include <tchar.h>#include <io.h>#define STATUS_SUCCESS      (0x00000000L) typedef LONG NTSTATUS;typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer;} LSA_UNICODE_STRING, *PLSA_UN

百度地图api抓取坐标实例

<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>百度地图API的使用</title> <!-- 百度地图API--> <script src="http://api.map.baidu.com/api?v=1.2" type="text/javascript"></scri

通过调用Twitter API抓取Twitter数据

国内研究weibo的人比较多,资料也相对较多,但是twitter的资料相对较少.今天简单说一下twitter api的使用.最近一小需求,采集含有指定关键词的twitter数据,瞬间想到写个爬虫来抓取,后来突然想到twitter应该有open api可用.使用了vpn翻墙之后简单的了解了twitter.com,决定直接使用 twitter api.由于twitter的open api现在也是基于oauth协议的,因此使用流程和国内一些社区比如说人人网,weibo的api的过程类似. 要想使用tw

百度地图POI数据爬取,突破百度地图API爬取数目“400条“的限制11。

1.POI爬取方法说明 1.1AK申请 登录百度账号,在百度地图开发者平台的API控制台申请一个服务端的ak,主要用到的是Place API.检校方式可设置成IP白名单,IP直接设置成了0.0.0.0/0比较方便. Place API 提供的接口用于返回查询某个区域的某类POI数据,且提供单个POI的详情查询服务,用户可以使用C#.C++.Java,Python等开发语言发送请求,接收json.xml的数据.关于Place API的具体使用可以参考:Place API Web服务API 1.2爬