转:EasyHook远程代码注入
最近一段时间由于使用MinHook的API挂钩不稳定,经常因为挂钩地址错误而导致宿主进程崩溃。听同事介绍了一款智能强大的挂钩引擎EasyHook。它比微软的detours好的一点是它的x64注入支持是免费开源的。不想微软的detours,想搞x64还得购买。
好了,闲话不多说,先下载EasyHook的开发库,当然有兴趣的同学可以下载源码进行学习。下载地址:http://easyhook.codeplex.com/releases/view/24401。我给的这个是2.6版本的。
EasyHook提供了两种模式的注入管理。一种是托管代码的注入,另一种是非托管代码的注入。我是学习C++的,所以直接学习了例子中的非托管项目UnmanagedHook。里面给了一个简单的挂钩MessageBeep API的示例。我需要将其改造成支持远程注入的。下面先给出钩子DLL代码:
- // dllmain.cpp : 定义 DLL 应用程序的入口点。
- #include "stdafx.h"
- #include "HookApi.h"
- #include "easyhook.h"
- #include "ntstatus.h"
- ptrCreateFileW realCreateFileW = NULL;
- ptrCreateFileA realCreateFileA = NULL;
- HMODULE hKernel32 = NULL;
- TRACED_HOOK_HANDLE hHookCreateFileW = new HOOK_TRACE_INFO();
- TRACED_HOOK_HANDLE hHookCreateFileA = new HOOK_TRACE_INFO();
- NTSTATUS statue;
- ULONG HookCreateFileW_ACLEntries[1] = {0};
- ULONG HookCreateFileA_ACLEntries[1] = {0};
- int PrepareRealApiEntry()
- {
- OutputDebugString(L"PrepareRealApiEntry()\n");
- // 获取真实函数地址
- HMODULE hKernel32 = LoadLibrary(L"Kernel32.dll");
- if (hKernel32 == NULL)
- {
- OutputDebugString(L"LoadLibrary(L\"Kernel32.dll\") Error\n");
- return -6002;
- }
- OutputDebugString(L"LoadLibrary(L\"Kernel32.dll\") OK\n");
- realCreateFileW = (ptrCreateFileW)GetProcAddress(hKernel32, "CreateFileW");
- if (realCreateFileW == NULL)
- {
- OutputDebugString(L"(ptrCreateFileW)GetProcAddress(hKernel32, \"CreateFileW\") Error\n");
- return -6007;
- }
- OutputDebugString(L"(ptrCreateFileW)GetProcAddress(hKernel32, \"CreateFileW\") OK\n");
- realCreateFileA = (ptrCreateFileA)GetProcAddress(hKernel32, "CreateFileA");
- if (realCreateFileA == NULL)
- {
- OutputDebugString(L"(ptrCreateFileA)GetProcAddress(hKernel32, \"CreateFileA\") Error\n");
- return -6007;
- }
- OutputDebugString(L"(ptrCreateFileA)GetProcAddress(hKernel32, \"CreateFileA\") OK\n");
- return 0;
- }
- void DoHook()
- {
- OutputDebugString(L"DoHook()\n");
- statue = LhInstallHook(realCreateFileW,
- MyCreateFileW,
- /*(PVOID)0x12345678*/NULL,
- hHookCreateFileW);
- if(!SUCCEEDED(statue))
- {
- switch (statue)
- {
- case STATUS_NO_MEMORY:
- OutputDebugString(L"STATUS_NO_MEMORY\n");
- break;
- case STATUS_NOT_SUPPORTED:
- OutputDebugString(L"STATUS_NOT_SUPPORTED\n");
- break;
- case STATUS_INSUFFICIENT_RESOURCES:
- OutputDebugString(L"STATUS_INSUFFICIENT_RESOURCES\n");
- break;
- default:
- WCHAR dbgstr[512] = {0};
- wsprintf(dbgstr, L"%d\n", statue);
- OutputDebugString(dbgstr);
- }
- OutputDebugString(L"LhInstallHook(GetProcAddress(hKernel32, \"CreateFileW\"),MyCreateFileW,(PVOID)0x12345678,hHookCreateFileW); Error\n");
- return;
- }
- OutputDebugString(L"Hook CreateFileW OK\n");
- statue = LhInstallHook(realCreateFileA,
- MyCreateFileA,
- /*(PVOID)0x12345678*/NULL,
- hHookCreateFileA);
- if(!SUCCEEDED(statue))
- {
- switch (statue)
- {
- case STATUS_NO_MEMORY:
- OutputDebugString(L"STATUS_NO_MEMORY\n");
- break;
- case STATUS_NOT_SUPPORTED:
- OutputDebugString(L"STATUS_NOT_SUPPORTED\n");
- break;
- case STATUS_INSUFFICIENT_RESOURCES:
- OutputDebugString(L"STATUS_INSUFFICIENT_RESOURCES\n");
- break;
- default:
- WCHAR dbgstr[512] = {0};
- wsprintf(dbgstr, L"%d\n", statue);
- OutputDebugString(dbgstr);
- }
- OutputDebugString(L"LhInstallHook(GetProcAddress(hKernel32, \"CreateFileA\"),MyCreateFileA,(PVOID)0x12345678,hHookCreateFileA); Error\n");
- return;
- }
- OutputDebugString(L"Hook CreateFileA OK\n");
- // 一定要调用这个函数,否则注入的钩子无法正常运行。
- LhSetExclusiveACL(HookCreateFileA_ACLEntries, 1, hHookCreateFileA);
- LhSetExclusiveACL(HookCreateFileW_ACLEntries, 1, hHookCreateFileW);
- }
- void DoneHook()
- {
- OutputDebugString(L"DoneHook()\n");
- // this will also invalidate "hHook", because it is a traced handle...
- LhUninstallAllHooks();
- // this will do nothing because the hook is already removed...
- LhUninstallHook(hHookCreateFileA);
- LhUninstallHook(hHookCreateFileW);
- // now we can safely release the traced handle
- delete hHookCreateFileA;
- hHookCreateFileA = NULL;
- delete hHookCreateFileW;
- hHookCreateFileW = NULL;
- // even if the hook is removed, we need to wait for memory release
- LhWaitForPendingRemovals();
- }
- BOOL APIENTRY DllMain( HMODULE hModule,
- DWORD ul_reason_for_call,
- LPVOID lpReserved
- )
- {
- switch (ul_reason_for_call)
- {
- case DLL_PROCESS_ATTACH:
- {
- OutputDebugString(L"DllMain::DLL_PROCESS_ATTACH\n");
- // 准备好原始地址与目的地址
- int errCode = PrepareRealApiEntry();
- if (errCode != 0)
- {
- OutputDebugString(L"PrepareRealApiEntry() Error\n");
- return FALSE;
- }
- // 开始挂钩
- DoHook();
- break;
- }
- case DLL_THREAD_ATTACH:
- {
- OutputDebugString(L"DllMain::DLL_THREAD_ATTACH\n");
- break;
- }
- case DLL_THREAD_DETACH:
- {
- OutputDebugString(L"DllMain::DLL_THREAD_DETACH\n");
- break;
- }
- case DLL_PROCESS_DETACH:
- {
- OutputDebugString(L"DllMain::DLL_PROCESS_DETACH\n");
- // 卸载钩子
- DoneHook();
- break;
- }
- }
- return TRUE;
- }
- <pre name="code" class="cpp">// HookSvr.cpp
- #include "stdafx.h"
- #include "HookApi.h"
- #include "easyhook.h"
- HANDLE WINAPI MyCreateFileW(
- __in LPCWSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- )
- {
- HANDLE hHandle = NULL;
- // 执行钩子
- if (realCreateFileW == NULL)
- {
- OutputDebugString(L"realCreateFileW is NULL\n");
- return INVALID_HANDLE_VALUE;
- }
- else
- {
- OutputDebugString(L"realCreateFileW is not NULL\n");
- hHandle = (realCreateFileW)(lpFileName, dwDesiredAccess, dwShareMode,
- lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
- OutputDebugString(L"MyCreateFileW : ");
- OutputDebugString(lpFileName);
- OutputDebugString(L"\n");
- }
- return hHandle;
- }
- HANDLE WINAPI MyCreateFileA(
- __in LPCSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- )
- {
- HANDLE hHandle = NULL;
- // 执行钩子
- if (realCreateFileA == NULL)
- {
- OutputDebugString(L"realCreateFileA is NULL\n");
- return INVALID_HANDLE_VALUE;
- }
- else
- {
- OutputDebugString(L"realCreateFileA is not NULL\n");
- hHandle = (realCreateFileA)(lpFileName, dwDesiredAccess, dwShareMode,
- lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
- OutputDebugString(L"MyCreateFileW : ");
- OutputDebugStringA(lpFileName);
- OutputDebugString(L"\n");
- }
- return hHandle;
- }</pre><br>
- 钩子这一部分我弄了比较久,主要是API不熟悉,不过好在弄好了。
- <pre></pre>
- <p><br>
- </p>
- <p></p><pre name="code" class="cpp">// HookSvr.h
- #pragma once
- #include <Windows.h>
- #ifndef _M_X64
- #pragma comment(lib, "EasyHook32.lib")
- #else
- #pragma comment(lib, "EasyHook64.lib")
- #endif
- HANDLE WINAPI MyCreateFileW(
- __in LPCWSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
- typedef HANDLE (WINAPI *ptrCreateFileW)(
- __in LPCWSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
- extern ptrCreateFileW realCreateFileW;
- HANDLE WINAPI MyCreateFileA(
- __in LPCSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
- typedef HANDLE (WINAPI *ptrCreateFileA)(
- __in LPCSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
- extern ptrCreateFileA realCreateFileA;</pre><br>
- <br>
- <p></p>
- <p>接下来是注入工具,这里指提供核心代码。本来EasyHook还提供了一个叫<span style="color:black">Rh</span>InjectLibrary()方法直接注入,这种方法相当稳定,推荐使用。我本来也用它,但是发现注入会失败,所以就采用了比较通用的远程注入代码,如下:</p>
- <pre name="code" class="cpp">BOOL RtlFileExists(WCHAR* InPath)
- {
- HANDLE hFile;
- if((hFile = CreateFileW(InPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
- return FALSE;
- CloseHandle(hFile);
- return TRUE;
- }
- BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
- {
- TOKEN_PRIVILEGES tp;
- HANDLE hToken;
- LUID luid;
- if( !OpenProcessToken(GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
- &hToken) )
- {
- return FALSE;
- }
- if( !LookupPrivilegeValue(NULL, // lookup privilege on local system
- lpszPrivilege, // privilege to lookup
- &luid) ) // receives LUID of privilege
- {
- return FALSE;
- }
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Luid = luid;
- if( bEnablePrivilege )
- tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- else
- tp.Privileges[0].Attributes = 0;
- // Enable the privilege or disable all privileges.
- if( !AdjustTokenPrivileges(hToken,
- FALSE,
- &tp,
- sizeof(TOKEN_PRIVILEGES),
- (PTOKEN_PRIVILEGES) NULL,
- (PDWORD) NULL) )
- {
- return FALSE;
- }
- if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
- {
- //The token does not have the specified privilege.
- return FALSE;
- }
- return TRUE;
- }
- typedef DWORD (WINAPI *PFNTCREATETHREADEX)
- (
- PHANDLE ThreadHandle,
- ACCESS_MASK DesiredAccess,
- LPVOID ObjectAttributes,
- HANDLE ProcessHandle,
- LPTHREAD_START_ROUTINE lpStartAddress,
- LPVOID lpParameter,
- BOOL CreateSuspended,
- DWORD dwStackSize,
- DWORD dw1,
- DWORD dw2,
- LPVOID Unknown
- );
- BOOL MyCreateRemoteThread(HANDLE hProcess, LPTHREAD_START_ROUTINE pThreadProc, LPVOID pRemoteBuf)
- {
- HANDLE hThread = NULL;
- FARPROC pFunc = NULL;
- BOOL bHook;
- // 判断系统版本
- OSVERSIONINFO osvi;
- //BOOL bIsWindowsXPorLater;
- ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&osvi);
- if (osvi.dwMajorVersion == 6)
- {
- bHook = TRUE;
- }
- else
- {
- bHook = FALSE;
- }
- if(bHook) // Vista, 7, Server2008
- {
- pFunc = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateThreadEx");
- if( pFunc == NULL )
- {
- //GetLastError());
- return FALSE;
- }
- OutputDebugString(L"MyCreateRemoteThread");
- ((PFNTCREATETHREADEX)pFunc)(&hThread,
- 0x1FFFFF,
- NULL,
- hProcess,
- pThreadProc,
- pRemoteBuf,
- FALSE,
- NULL,
- NULL,
- NULL,
- NULL);
- if( hThread == NULL )
- {
- return FALSE;
- }
- }
- else // 2000, XP, Server2003
- {
- hThread = CreateRemoteThread(hProcess,
- NULL,
- 0,
- pThreadProc,
- pRemoteBuf,
- 0,
- NULL);
- if( hThread == NULL )
- {
- return FALSE;
- }
- }
- if( WAIT_FAILED == WaitForSingleObject(hThread, INFINITE) )
- {
- return FALSE;
- }
- return TRUE;
- }
- BOOL InjectDll(DWORD dwPID, const wchar_t *szDllName)
- {
- HANDLE hProcess = NULL;
- LPVOID pRemoteBuf = NULL;
- FARPROC pThreadProc = NULL;
- DWORD dwBufSize = wcslen(szDllName)*sizeof(wchar_t)+2;
- if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
- {
- return FALSE;
- }
- pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize,
- MEM_COMMIT, PAGE_READWRITE);
- WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName,
- dwBufSize, NULL);
- pThreadProc = GetProcAddress(GetModuleHandle(L"kernel32.dll"),
- "LoadLibraryW");
- if( !MyCreateRemoteThread(hProcess, (LPTHREAD_START_ROUTINE)pThreadProc, pRemoteBuf) )
- {
- return FALSE;
- }
- VirtualFreeEx(hProcess, pRemoteBuf, dwBufSize, MEM_RELEASE);
- CloseHandle(hProcess);
- return TRUE;
- }
- int DoInject(DWORD aPid, const WCHAR *aFullpath)
- {
- if (wcslen(aFullpath) <= 0)
- {
- return -1;
- }
- //判断dll是否存在
- HANDLE hFile = CreateFile(aFullpath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
- if(hFile != INVALID_HANDLE_VALUE)
- {
- DWORD dwsize = GetFileSize(hFile, NULL);
- CloseHandle(hFile);
- if (dwsize < 10)
- {
- return -2;
- }
- }
- else
- {
- return -3;
- }
- BOOL bSuc=SetPrivilege(SE_DEBUG_NAME, TRUE);
- bSuc=InjectDll((DWORD)aPid, aFullpath);
- if (bSuc)
- {
- return -4;
- }
- return 0;
- }
- // 真实注入的时候应该这样调用
- DoInject(m_processId, L"E:\\src\\easyhook\\trunk\\Debug\\x86\\HookSvr.dll");
- </pre><br>
- 这样就能保证注入的钩子能正常工作了。
- 4楼 SpiritMFC 2013-03-26 15:43发表 [回复]
- 你好~ 能提供能运行的源码嘛?
我用你的方法正常exe可以hook成功,
但是DLL注入后钩子无法工作。
困扰数天的问题了。
求帮助!
还有 C++的话这个库能实现全局钩子嘛?
- Re: baggiowangyu 2013-03-29 09:24发表 [回复]
- 回复SpiritMFC:我给的例子就是源代码了哇,那时候研究到那里就没有继续往下了。应该是你注入之后挂钩写的不对导致的。
你指的全局钩子是什么概念?全局消息钩子么?目前我知道的是这个可以实现指定进程的挂钩。
- 3楼 lsssml1990 2012-10-26 12:22发表 [回复]
- 这个代码可以直接用不?
- 2楼 baggiowangyu 2012-06-23 14:02发表 [回复]
- 一同学习,一同学习
转:EasyHook远程代码注入的更多相关文章
- EasyHook远程进程注入并hook api的实现
EasyHook远程进程注入并hook api的实现 http://blog.csdn.net/v6543210/article/details/44276155
- C语言实现远程代码注入
#include <windows.h> #include <iostream> #define STRLEN 20 typedef struct _DATA { DWORD ...
- windows:shellcode 代码远程APC注入和加载
https://www.cnblogs.com/theseventhson/p/13197776.html 上一章介绍了通用的shellcode加载器,这个加载器自己调用virtualAlloc分配 ...
- Windows下的代码注入
木马和病毒的好坏很大程度上取决于它的隐蔽性,木马和病毒本质上也是在执行程序代码,如果采用独立进程的方式需要考虑隐藏进程否则很容易被发现,在编写这类程序的时候可以考虑将代码注入到其他进程中,借用其他进程 ...
- ecshop 全系列版本网站漏洞 远程代码执行sql注入漏洞
ecshop漏洞于2018年9月12日被某安全组织披露爆出,该漏洞受影响范围较广,ecshop2.73版本以及目前最新的3.0.3.6.4.0版本都受此次ecshop漏洞的影响,主要漏洞是利用远程代码 ...
- 注入攻击-SQL注入和代码注入
注入攻击 OWASP将注入攻击和跨站脚本攻击(XSS)列入网络应用程序十大常见安全风险.实际上,它们会一起出现,因为 XSS 攻击依赖于注入攻击的成功.虽然这是最明显的组合关系,但是注入攻击带来的不仅 ...
- MongoDB ‘conn’Mongo 对象远程代码执行漏洞
漏洞名称: MongoDB ‘conn’Mongo 对象远程代码执行漏洞 CNNVD编号: CNNVD-201307-497 发布时间: 2013-07-25 更新时间: 2013-07-25 危害等 ...
- 使用VC++通过远程进程注入来实现HOOK指定进程的某个API
前阵子读到一篇关于<HOOK API入门之Hook自己程序的MessageBoxW>的博客,博客地址:http://blog.csdn.net/friendan/article/detai ...
- 远程线程注入方法CreateRemoteThread
最近在整理学习Windows注入方面的知识,这个远程注入前面早写过,现在看看人家博客的理解整理,整理, 需要源码的可以到我的github上下载. 链接是 https://github.com/Ars ...
随机推荐
- POJ 3274 Gold Balanced Lineup
Gold Balanced Lineup Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10924 Accepted: 3244 ...
- POJ 3041 Asteroids
最小点覆盖数==最大匹配数 Asteroids Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12678 Accepted: ...
- HDU 4858 项目管理(邻接表 暴力模拟)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4858 我们建造了一个大项目!这个项目有n个节点,用很多边连接起来,并且这个项目是连通的! 两个节点间可 ...
- 快速诊断Linux性能
导读 当你为了解决一个性能问题登录到一台 Linux 服务器:在第一分钟你应该检查些什么? 通过运行下面十个命令,你就能在六十秒内粗略地了解系统正在运行的进程及资源使用情况.通过查看这些命令输出的错误 ...
- sql注入学习小结
/* 转载请注明出处,By:珍惜少年时 小知识,只是放在博客吃饭时无聊看看,大牛勿喷. */ 珍惜少年时博客,专注网络安全 web渗透测试 00x1爆所有库: mysql> select sch ...
- 用sed删除空行
用sed删除空行 我的代码如下:class Song def initialize(name) @name = name end def tell puts @nam ...
- android 自定义Dialog背景透明及显示位置设置
先贴一下显示效果图,仅作参考: 代码如下: 1.自定义Dialog public class SelectDialog extends AlertDialog{ public SelectDialog ...
- 【Django】如何自定义manage.py命令? 达到启动后台进程的目的?
代码: #-*- coding:utf- -*- """ The handle active user mail send """ from ...
- 【SpringMVC】SpringMVC系列10之视图与视图解析器
10.视图与视图解析器 10.1.概述 请求处理方法执行完成后,最终返回一个 ModelAndView处理方法,Spring MVC 也会在内部将它们装配成一个ModelAndView 对象, ...
- HashMap实现原理分析(详解)
1. HashMap的数据结构 http://blog.csdn.net/gaopu12345/article/details/50831631 ??看一下 数据结构中有数组和链表来实现对数据的存 ...