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;
}

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

运行结果截图:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值