notepad hook

本文介绍了一个利用DLL注入和API Hook技术监控记事本读写操作的程序。程序首先释放DLL到文件系统,然后通过注册表操作实现开机自启动。通过枚举进程找到notepad.exe并注入DLL,DLL使用Inline Hook对ReadFile和WriteFile进行hook,记录读写信息到日志文件。测试结果显示程序能有效监控记事本操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0x00 前言

昨天花了半天写了个四不像的玩意儿,本来打算以恶意代码的方式去写,但今天不怎么想完 善功能了,所以全局hook和自删除之类的就没有了(其实是debug太麻烦。),结果就是这 个程序很沙雕,你必须先打开记事本再运行它才行。不过获取记事本信息是没什么问题的。


0x01 行为

完全是想到什么写什么,所以有些功能完全没发挥作用呢。。 PS:这里所有生成的文件都存放在你的C:/User/username/Documents/文件夹下。

  1. 要注入的DLL文件以资源的形式嵌在启动器中,首先将其释放到文件夹下,名为 notepadhook.dll
  2. 复制启动器自身到文件夹下
  3. 将复制的启动器路径添加到注册表的自启动项中
  4. 枚举进程快照,找到notepad.exe,将DLL文件注入
  5. DLL文件使用Inline hook对ReadFile和WriteFile进行hook,将读取和保存的信息写入到 readlog.txt和writelog.txt

0x02 启动器

启动器本质上就是个DLL注入器,不过DLL文件以资源的形式嵌入到自身当中,所以要先释 放DLL文件到磁盘中。自我复制完全是为了开机自启动才写的,但没有谁一开机就会启动记 事本,所以运行起来是没用的,本来想hook CreateProcess将所有子进程都进行注入,以 此达到一旦启动记事本就会被hook的效果,但完全不想debug了。。。
0x03 notepadhook.dll hook的功能由这个DLL来实现,虽然说可以对native层的API进行hook,但我去看了眼文档,参数太过复杂,就hook记事本来说,hook ReadFile和WriteFile两个ring3层 API完全足够了。hook方式使用的是Inline hook中的mov eax, address; jmp rax这种方 式,这在64位中很常见。hook之后就是将数据缓冲区写入到readlog.txt和writelog.txt中了。


0x04 注册表操作

在这个程序中,对注册表进行了两个操作。 一是设置将自我复制的启动器添加到自启动的子键中,即 HKEY_CURRENT_USE\Software\Microsoft\Windows\CurrentVersion\Run,创建一个 新的键值,并将其值设置为路径即可
二是用于获取C:/User/username/Documents/这个路径,因为username是未知的,每个 计算机的用户名不同,可以通过获取 Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders这个键中的 Personal的值来获取这个路径,这应该是个缺省值,可以修改的。


0x05 枚举进程

这里我们只针对notepad进行hook,而DLL注入需要知道进程的pid,Windows貌似没有 提供直接通过进程名来获取pid的API,所以若想完成这个操作,通常可以通过枚举系统进 程快照的方式来获取进行信息,其实就是遍历一个类似链表的东西,熟悉下API就行了

DWORD GetPrcessIdByProcessName(const char* pszProcessName)
{
	DWORD dwProcessId = 0;
	PROCESSENTRY32 pe32 = { 0 };
	HANDLE hSnapshot = NULL;
	BOOL bRet = FALSE;
	::RtlZeroMemory(&pe32, sizeof(pe32));
	pe32.dwSize = sizeof(pe32);

	hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

	bRet = ::Process32First(hSnapshot, &pe32);
	while (bRet)
	{
		if (!::lstrcmpi(pe32.szExeFile, pszProcessName))
		{
			dwProcessId = pe32.th32ProcessID;
			break;
		}
		bRet = ::Process32Next(hSnapshot, &pe32);
	}
	return dwProcessId;
}


0x06 DLL注入

DLL注入是一种从外部操纵目标进程空间的方式,可以为程序添加额外功能,这种功能可以 是补丁性质的,也可以是恶意的。DLL注入其实可以研究得比较深,不过为了好写,这个程 序只用了最最常见的DLL注入方式——远线程注入。远线程注入的核心是 CreateRemoteThread函数,通过这个函数在某个进程中开启一个线程。具体步骤如下:
1.打开目标进程并获取其句柄 2.在目标进程中分配一块缓冲区 3.将DLL文件路径写入该缓冲区 4.获取LoadLibraryA/LoadLibraryW函数的地址 5.利用CreateRemoteThread开启一个线程,这个线程调用LoadLibrary函数,以DLL文件 路径为参数


0x07 API Hook

API Hook根据实现方式可以分为3类,Address Hook,Inline Hook和利用异常处理 Hook。 Address Hook的本质就是劫持函数表,有pwn基础的同学可以类比GOT覆盖,这样的表有 很多,如IAT,虚函数表,甚至一些系统中断表之类的。 Iline Hook就是一种简单的跳转操作,它直接修改函数开头的指令,令要hook的API开头跳 转到我们自定义的函数中,常用的有mov rax, address; jmp rax    push address; retn这 样的一些指令,不过Inline Hook操作的直接是代码段,所以有时会出现一些奇怪的问题。 利用异常处理进行hook感觉要相对复杂些,作为代表的就是模拟一个调试器的行为来进行 hook,在要hook的API开头写入0xcc,运行到此处时就会触发一个BreakPoint异常,然后 交给我们的调试器来处理,不过写起来挺麻烦。 Hook技术在PC端和移动端都很受欢迎,也出现了许多hook框架,利用这些框架可以更好 的完成某种功能,而非总是调用底层的API,这是很麻烦的。


0x08 测试

首先打开一个记事本,然后启动程序


打开一个文本文件

修改一下然后保存

去到我的文档文件夹下

可以看到生成了4个文件,第一个是释放的DLL文件,第二个是自我复制的文件,后两个就是获取的信息了,打开看看

可以看到除了有我们打开的那个文件,还有其他一些乱七八糟的,这可能是ReadFile这个函数调用时都被钩取了。

这里面就很干净了,保存的是修改后的文本。

注意测试完成后要删除注册表启动项哦

0x09 总结

复习了下Windows API吧。。。

目前最好的EasyHook的完整Demo程序,包括了Hook.dll动态库和Inject.exe注入程序。 Hook.dll动态库封装了一套稳定的下钩子的机制,以后对函数下钩子,只需要填下数组表格就能实现了,极大的方便了今后的使用。 Inject.exe部分是用MFC写的界面程序,只需要在界面上输入进程ID就能正确的HOOK上相应的进程,操作起来非常的简便。 这个Demo的代码风格也非常的好,用VS2010成功稳定编译通过,非常值得下载使用。 部分代码片段摘录如下: //【Inject.exe注入程序的代码片段】 void CInjectHelperDlg::OnBnClickedButtonInjectDllProcessId() { ////////////////////////////////////////////////////////////////////////// //【得到进程ID值】 UINT nProcessID = 0; if (!GetProcessID(nProcessID)) { TRACE(_T("%s GetProcessID 失败"), __FUNCTION__); return; } ////////////////////////////////////////////////////////////////////////// //【得到DLL完整路径】 CString strPathDLL; if (!GetDllFilePath(strPathDLL)) { TRACE(_T("%s GetDllFilePath 失败"), __FUNCTION__); return; } ////////////////////////////////////////////////////////////////////////// //【注入DLL】 NTSTATUS ntStatus = RhInjectLibrary(nProcessID, 0, EASYHOOK_INJECT_DEFAULT, strPathDLL.GetBuffer(0), NULL, NULL, 0); if (!ShowStatusInfo(ntStatus)) { TRACE(_T("%s ShowStatusInfo 失败"), __FUNCTION__); return; } } //【Hook.dll动态库的代码片段】 extern "C" __declspec(dllexport) void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* InRemoteInfo) { if (!DylibMain()) { TRACE(_T("%s DylibMain 失败"), __FUNCTION__); return; } } FUNCTIONOLDNEW_FRMOSYMBOL array_stFUNCTIONOLDNEW_FRMOSYMBOL[]= { {_T("kernel32"), "CreateFileW", (void*)CreateFileW_new}, {_T("kernel32"), "CreateFileA", (void*)CreateFileA_new}, {_T("kernel32"), "ReadFile", (void*)ReadFile_new} }; BOOL HookFunctionArrayBySymbol() { /////////////////////////////////////////////////////////////// int nPos = 0; do { /////////////////////////////// FUNCTIONOLDNEW_FRMOSYMBOL* stFunctionOldNew = &g_stFUNCTIONOLDNEW_FRMOSYMBOL[nPos]; if (NULL == stFunctionOldNew->strModulePath) { break; } /////////////////////////////// if (!HookFunctionBySymbol(stFunctionOldNew->strModulePath, stFunctionOldNew->strNameFunction, stFunctionOldNew->pFunction_New)) { TRACE(_T("%s HookFunctionBySymbol 失败"), __FUNCTION__); return FALSE; } } while(++nPos); /////////////////////////////////////////////////////////////// return TRUE; } HANDLE WINAPI CreateFileW_new( PWCHAR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ) { TRACE(_T("CreateFileW_new. lpFileName = %s"), lpFileName); return CreateFileW( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值