win32 拦截API

下面代码演示了向“记事本”程序(NOTEPAD.EXE)的进程地址空间中拦截API,大致原理如下:


1. 提升注入(注意和“被注入”的区别)程序的进程访问权限

2. 随便打开一个记事本文件,注意是用NOTEPAD.EXE打开的

3. 查找NOTEPAD.EXE对应的进程ID,即Process ID

4. 以所有权限(包括read/write)打开NOTEPAD.EXE的进程ID

5. 在NOTEPAD.EXE的进程ID地址空间中,申请一块内存

6. 向刚刚申请的内存中,写入我们想要写的任何代码(注意:注入的代码中全部都用指针的形式调用相关数据和函数)

7. 我们写的代码不会自动执行,当你编辑被拦截的记事本内容,然后按 Ctrl+S 保存后,会调用CreateFileW(...)这个API,这个API已经被我们做过手脚了,会跳转到我们写的任何函数处,并执行,执行完后,将正确的API前10个字节恢复成原来的样子,然后清理现场,不留痕迹,就ok啦


注意该程序必须在Release版本下运行,如果是DeBug版本的话,因为编译器没做优化和加了一些debug代码,所以会内存读写报错


//
//拦截 CreateFileW(...) API的示例代码
//
//整理:过客    
//邮箱:386520874@qq.com    
//日期:2014.04.06

#include <stdio.h>
#include <windows.h>
#include <wchar.h>
#include <TlHelp32.h>

typedef struct _RemoteParam
{
	DWORD dwCreateFile;
	DWORD dwMessageBox;
	DWORD dwGetCurrentProcess;
	DWORD dwWriteProcessMemory;
	unsigned char szOldCode[10];
	DWORD FunAddr;
	wchar_t info[260];
} RemoteParam, * PRemoteParam;

typedef HANDLE (__stdcall * PFN_CREATEFILE)(LPCWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE);
typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCWSTR, LPCWSTR, DWORD);
typedef BOOL (__stdcall * PFN_WRITEPROCESSMEMORY)(HANDLE,LPVOID,LPCVOID,SIZE_T,SIZE_T*); 
typedef HANDLE (__stdcall * PFN_GETCURRENTPROCESS)(void);

void HookCreateFile(LPVOID lParam) 
{
	RemoteParam* pRP = (RemoteParam*)lParam;
	
	DWORD NextIpAddr = 0; 
	DWORD dwParamaAddr = 0;

	HANDLE RetFpHdl = INVALID_HANDLE_VALUE;
	LPCWSTR lpFileName; 
	DWORD dwDesiredAccess; 
	DWORD dwShareMode;
	LPSECURITY_ATTRIBUTES lpSecurityAttributes; 
	DWORD dwCreationDisposition; 
	DWORD dwFlagsAndAttributes; 
	HANDLE hTemplateFile; 
	PFN_CREATEFILE pfnCreatefile = (PFN_CREATEFILE)pRP->dwCreateFile;

	//下面的汇编代码是将Createfile(...)里面的7个参数和另外两个变量(dwParamaAddr和NextIpAddr)保存到变量中,以便后面调用
	__asm 
	{ 
		MOV EAX,[EBP+8]
		MOV [dwParamaAddr], EAX
		MOV EAX,[EBP+12]
		MOV [NextIpAddr], EAX
		MOV EAX,[EBP+16]
		MOV [lpFileName], EAX
		MOV EAX,[EBP+20]
		MOV [dwDesiredAccess], EAX
		MOV EAX,[EBP+24]
		MOV [dwShareMode], EAX
		MOV EAX,[EBP+28]
		MOV [lpSecurityAttributes], EAX
		MOV EAX,[EBP+32]
		MOV [dwCreationDisposition], EAX
		MOV EAX,[EBP+36]
		MOV [dwFlagsAndAttributes], EAX
		MOV EAX,[EBP+40]
		MOV [hTemplateFile], EAX
	}

	PFN_MESSAGEBOX pfnMessageBox = (PFN_MESSAGEBOX)pRP->dwMessageBox;

	int allowFlag = pfnMessageBox(NULL, lpFileName, pRP->info, MB_ICONWARNING | MB_YESNO);

	PFN_GETCURRENTPROCESS pfnGetCurrentProcess = (PFN_GETCURRENTPROCESS)pRP->dwGetCurrentProcess; 
	PFN_WRITEPROCESSMEMORY pfnWriteProcessMemory = (PFN_WRITEPROCESSMEMORY)pRP->dwWriteProcessMemory;
	pfnWriteProcessMemory(pfnGetCurrentProcess(), (LPVOID)pfnCreatefile, (LPCVOID)pRP->szOldCode, 10, NULL);

	RetFpHdl = pfnCreatefile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); 

	//下面代码是善后工作,这个非常重要,如果没有的话,EIP将回不到调用Createfile(...)的下一条命令,这条命令在"notepad.exe"的名字空间
	//而不是kernel32.dll的名字空间中,要切记。
	__asm 
	{
		POP EDI
		POP ESI
		POP EBX
		MOV EDX, [NextIpAddr] //调用Createfile(...)这一命令的下一条命令地址,
		MOV EAX, [RetFpHdl] //函数返回值要放到EAX寄存器里,这一句可省略,原因是pfnCreatefile(...)会自动将结果存入EAX
		MOV ESP, EBP
		POP EBP
		MOV ESP, EBP
		PUSH EDX
		RET //ret指令用栈中的数据(即edx里面的地址),修改IP的内容,注意不修改CS的内容,retf才是 
	}
}

//提升进程访问权限
BOOL enableDebugPriv()
{
	HANDLE hToken;
	LUID sedebugnameValue;
	TOKEN_PRIVILEGES tkp;

	if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
	{
		return FALSE;
	}
	if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
	{
		CloseHandle(hToken);
		return FALSE;
	}
	tkp.PrivilegeCount = 1;
	tkp.Privileges[0].Luid = sedebugnameValue;
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //特权启用
	if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) //启用指定访问令牌的特权
	{
		CloseHandle(hToken);
		return FALSE;
	}
	return TRUE;
}

//根据进程名称得到进程ID,如果有多个运行实例的话,返回第一个枚举到的进程的ID
DWORD processNameToId(LPCTSTR lpszProcessName)
{
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	PROCESSENTRY32 pe;
	pe.dwSize = sizeof(PROCESSENTRY32);
	if(!Process32First(hSnapshot, &pe))
	{
		MessageBox(NULL, "The frist entry of the process list has not been copyied to the buffer", "Notice", MB_ICONINFORMATION | MB_OK);
		return 0;
	}
	while(Process32Next(hSnapshot, &pe)) //循环查找下一个进程
	{
		if(!strcmp(lpszProcessName, pe.szExeFile)) //找到了
		{
			return pe.th32ProcessID;
		}
	}

	return 0;
}

//==============================================
int main(int argc, char* argv[]) 
{
	//提升进程访问权限
	if(!enableDebugPriv()) 
	{ 
		printf("提升进程访问权限 Error!\n"); 
		return -1; 
	}

	//等待输入进程名称,注意大小写匹配
	char szExeName[MAX_PATH] = { 0 };
//	cout << "Please input the name of target process !" << endl;
//	cin >> szExeName; //接收命令行输入的字符串
//	cout << szExeName << endl;
//	strcpy(szExeName,"notepad.exe");
//	scanf("%s",szExeName);
	sprintf(szExeName,"NOTEPAD.EXE");
 
	DWORD dwProcessId = processNameToId(szExeName); //Name转换成ID
	if(dwProcessId == 0)
	{
		MessageBox(NULL, "The target process have not been found !", "Notice", MB_ICONINFORMATION | MB_OK);
		return -1;
	}

	HANDLE hTargetProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, dwProcessId); 
	if(hTargetProcess == NULL) 
	{ 
		printf("OpenProcess Error!\n"); 
		return -1; 
	}
	
	//定义线程体的大小,实际分配的内存大小是页内存大小的整数倍
	int size_Func=1024*8;

	DWORD dwFunAddr = (DWORD)VirtualAllocEx(hTargetProcess, NULL, size_Func, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 
	if((LPVOID)dwFunAddr == NULL) 
	{ 
		printf("申请线程内存失败!\n"); 
		CloseHandle(hTargetProcess); 
		return -1; 
	}

	DWORD dwPramaAddr = (DWORD)VirtualAllocEx(hTargetProcess, NULL, sizeof(RemoteParam), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if((LPVOID)dwPramaAddr == NULL) 
	{ 
		printf("申请参数内存失败!\n"); 
		CloseHandle(hTargetProcess); 
		return -1; 
	}

	printf("\n线程内存地址:%.8x\n参数内存地址:%.8x\n", dwFunAddr, dwPramaAddr);
	RemoteParam RParam;
	ZeroMemory(&RParam, sizeof(RParam));
	HMODULE hKernel32 = LoadLibrary("kernel32.dll");
	HMODULE hUser32 = LoadLibrary("user32.dll");

	RParam.dwCreateFile = (DWORD)GetProcAddress(hKernel32, "CreateFileW");
	RParam.dwGetCurrentProcess = (DWORD)GetProcAddress(hKernel32, "GetCurrentProcess");
	RParam.dwWriteProcessMemory = (DWORD)GetProcAddress(hKernel32, "WriteProcessMemory");
	RParam.dwMessageBox = (DWORD)GetProcAddress(hUser32, "MessageBoxW");

	wchar_t str2[]={L"我拦截API成功了,哈哈^o^"};
	::wmemcpy_s(RParam.info,sizeof(RParam.info),str2,sizeof(str2));
	for(int i=15; i<31; i++){RParam.info[i]=L'\0';}

	unsigned char oldcode[10]; 
	unsigned char newcode[10]; 
	int praadd = (int)dwPramaAddr; 
	int threadadd = (int)dwFunAddr; 
	newcode[4] = praadd>>24; 
	newcode[3] = (praadd<<8)>>24; 
	newcode[2] = (praadd<<16)>>24; 
	newcode[1] = (praadd<<24)>>24; 
	newcode[0] = 0x68; //0x68: push newcode[1..4],参数先压栈

	int offsetaddr = threadadd - (int)RParam.dwCreateFile - 10 ; 
	newcode[9] = offsetaddr>>24; 
	newcode[8] = (offsetaddr<<8)>>24; 
	newcode[7] = (offsetaddr<<16)>>24; 
	newcode[6] = (offsetaddr<<24)>>24; 
	newcode[5] = 0xE8; //0xE8: call newcode[6..9],然后调用函数

	printf("NewCode:"); 
	for(int j = 0; j < 10; j++){printf("0x%.2x ",newcode[j]);}
	printf("\n");

	DWORD dwRead = 0;

	if(!ReadProcessMemory(GetCurrentProcess(), (LPCVOID)RParam.dwCreateFile, oldcode, 10, &dwRead)) 
	{
		printf("read error");
		CloseHandle(hTargetProcess);
		FreeLibrary(hKernel32);
		return -1;
	}

	strcat((char*)RParam.szOldCode, (char*)oldcode);
	RParam.FunAddr = dwFunAddr;

	printf("RParam.dwCreateFile:%.8x\nRParam.dwMessageBox:%.8x\nRParam.dwGetCurrentProcess:%.8x\nRParam.dwWriteProcessMemory:%.8x\nRParam.FunAddr:%.8x\n", 
		RParam.dwCreateFile, RParam.dwMessageBox, RParam.dwGetCurrentProcess, RParam.dwWriteProcessMemory, RParam.FunAddr); 
	
	//RParam.szOldCode[i]里面存放的是kernel32.dll里面的CreateFileW函数的前10个字节
	printf("RParam.szOldCode:");
	for(int i = 0; i< 10; i++){printf("0x%.2x ", RParam.szOldCode[i]);}
	printf("\n"); 

	DWORD dwWrite = 0;

	if(!WriteProcessMemory(hTargetProcess, (LPVOID)dwFunAddr, (LPVOID)&HookCreateFile, size_Func, &dwWrite))
	{
		printf("WriteRemoteProcessesMemory Error 1 !\n");
		CloseHandle(hTargetProcess);
		FreeLibrary(hKernel32);
		return -1;
	}

	if(!WriteProcessMemory(hTargetProcess, (LPVOID)dwPramaAddr, (LPVOID)&RParam, sizeof(RemoteParam), &dwWrite))
	{
		printf("WriteRemoteProcessesMemory Error 2 !\n");
		CloseHandle(hTargetProcess);
		FreeLibrary(hKernel32);
		return -1;
	}

	//将dwPid所在的进程的CreateFile API函数入口处前10个字节替换掉,当dwPid进程一旦调用CreateFile,就会先读取这10个字节
	//实际上这10个字节是调用dwFunAddr处的函数,这个函数就是HookCreateFile
	if(!WriteProcessMemory(hTargetProcess, (LPVOID)RParam.dwCreateFile, (LPVOID)newcode, 10, &dwWrite))
	{
		printf("WriteRemoteProcessesMemory Error 3 !\n");
		CloseHandle(hTargetProcess);
		FreeLibrary(hKernel32);
		return -1;
	}

	printf("\n已经将代码注入到目标进程(notepad.exe),祝好运!!!\n");
	CloseHandle(hTargetProcess);
	FreeLibrary(hKernel32);

	system("pause");

	return 0;
}

--------------------------------------------------------------

运行结果截图:


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "精通Win32 API编程"是一本讲解Windows操作系统下API编程的书籍。该书的主要内容围绕Win32 API以及如何使用API来开发Windows应用程序展开。 Win32 API是一套应用程序接口,它提供了访问Windows操作系统的功能和资源的一系列函数和服务。精通Win32 API编程的PDF为读者提供了全面而深入的知识和技巧,使他们能够充分利用Win32 API来创建强大、高效、功能丰富的Windows应用程序。 该书的内容包括Win32 API的核心组件、常用编程概念和技术、消息处理、图形界面设计、内存管理、多线程编程、网络编程等。不仅介绍了基础知识,还着重讲解了高级和复杂的编程技术与技巧。 读者通过学习该书可以掌握使用Win32 API进行窗口和控件的创建、消息的处理、内存的管理、图形的绘制,以及文件和网络的操作等重要内容。此外,书中还介绍了调试和优化Windows应用程序的方法,帮助读者解决日常开发过程中遇到的各种问题。 "精通Win32 API编程"的PDF不仅对想要深入了解Windows编程的开发者有很大帮助,也适合计算机科学相关专业的学生学习。通过阅读该书,读者能够提升Windows应用程序开发的技能和水平,实现更高效、更稳定、更灵活的应用程序。 ### 回答2: 精通Win32 API编程是一本覆盖广泛的书籍,它涵盖了使用Win32 API进行Windows操作系统编程的方方面面。该书的主要目标是帮助读者深入理解Win32 API的用法和原理,并掌握在Windows平台上开发应用程序的技巧。 在这本书中,读者将学习如何使用Win32 API来创建窗口、处理窗口消息、绘制图形、处理文件I/O操作、实现多线程等。此外,该书还详细介绍了常见的Win32 API函数和结构体,以及它们的用法和参数。 这本书的特色之一是它深入探讨了Win32 API的内部工作原理。它解释了消息循环、窗口过程、消息处理机制等概念,并提供了大量的代码示例和实践案例,帮助读者更好地理解和应用这些概念。 此外,这本书还介绍了一些高级的Win32 API编程技巧,比如使用API Hooking进行函数的拦截和修改,通过定时器实现定时任务,以及使用消息队列实现进程间通信等。这些技巧可以帮助读者更好地定制和优化Windows应用程序。 总的来说,精通Win32 API编程是一本非常全面和深入的书籍,它适合那些已经具备一定编程基础的读者,并且想要深入学习和掌握Win32 API编程技术的人。通过学习这本书,读者可以充分利用Win32 API的强大功能,开发出高效、功能丰富的Windows应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值