前阵子读到一篇关于《HOOK API入门之Hook自己程序的MessageBoxW》的博客,博客地址:http://blog.csdn.net/friendan/article/details/12222651,感觉写的很好但这篇博客主要讲的是本进程(本程序)的API HOOK那么如何将DLL注入到远程进程并进行API HOOK呢,好了废话不多说直接动手实践。

创建DLL动态库(我是在vs2008上实现的)

新建项目

创建一个名为MyDLL(名字随便)win32项目(我创建的是win32  DLL)点击确定

选择下一步

选择DLL,并点击完成

完成后到这个界面选择源文件中的dllmain.cpp如下图

这样就已经创建好一个DLL了,创建好了应该在里面做点什么吧,那么下面我们就动手实践吧:)。

我们这次HOOK的依然是MessageBoxW这个API。

直接上代码:

 #include "stdafx.h"

 //原函数类型定义
typedef int (WINAPI* MsgBoxW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
MsgBoxW OldMsgBoxW = NULL;//指向原函数的指针
FARPROC pfOldMsgBoxW; //指向函数的远指针
BYTE OldCode[]; //原系统API入口代码
BYTE NewCode[]; //原系统API新的入口代码(jmp xxxxxxxx) HANDLE hProcess = NULL;//本程序进程句柄
HINSTANCE hInst = NULL;//API所在的dll文件句柄 void HookOn();
void HookOff();
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
HookOff();//调用原函数之前,记得先恢复HOOK呀,不然是调用不到的
//如果不恢复HOOK,就调用原函数,会造成死循环
//毕竟调用的还是我们的函数,从而造成堆栈溢出,程序崩溃。 int nRet = ::MessageBoxW(hWnd, L"哈哈,MessageBoxW被HOOK了", lpCaption, uType); HookOn();//调用完原函数后,记得继续开启HOOK,不然下次会HOOK不到。 return nRet;
} //开启钩子的函数
void HookOn()
{
if ( NULL == hProcess)
{
return;
} DWORD dwTemp=;
DWORD dwOldProtect; //修改API函数入口前个字节为jmp xxxxxx
VirtualProtectEx(hProcess,pfOldMsgBoxW,,PAGE_READWRITE,&dwOldProtect);
WriteProcessMemory(hProcess,pfOldMsgBoxW,NewCode,,);
VirtualProtectEx(hProcess,pfOldMsgBoxW,,dwOldProtect,&dwTemp); } //关闭钩子的函数
void HookOff()
{
if ( NULL == hProcess)
{
return;
} DWORD dwTemp=;
DWORD dwOldProtect; //恢复API函数入口前个字节
VirtualProtectEx(hProcess, pfOldMsgBoxW, , PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, pfOldMsgBoxW, OldCode, , );
VirtualProtectEx(hProcess, pfOldMsgBoxW, , dwOldProtect, &dwTemp);
} //获取API函数入口前个字节
//旧入口前个字节保存在前面定义的字节数组BYTE OldCode[5]
//新入口前个字节保存在前面定义的字节数组BYTE NewCode[5]
void GetApiEntrance()
{ //获取原API入口地址
HMODULE hmod = ::LoadLibrary( L"User32.dll" );
OldMsgBoxW = (MsgBoxW)::GetProcAddress(hmod, "MessageBoxW");
pfOldMsgBoxW = (FARPROC)OldMsgBoxW; if (NULL == pfOldMsgBoxW)
{
MessageBox(NULL, L"获取原API入口地址出错", L"error!", );
return;
} // 将原API的入口前个字节代码保存到OldCode[]
_asm
{
lea edi,OldCode //获取OldCode数组的地址,放到edi
mov esi,pfOldMsgBoxW //获取原API入口地址,放到esi
cld //方向标志位,为以下两条指令做准备
movsd //复制原API入口前个字节到OldCode数组
movsb //复制原API入口第个字节到OldCode数组
} NewCode[]=0xe9;//实际上xe9就相当于jmp指令 //获取MyMessageBoxW的相对地址,为Jmp做准备
//int nAddr= UserFunAddr –SysFunAddr - (我们定制的这条指令的大小);
//Jmp nAddr;
//(我们定制的这条指令的大小), 这里是,个字节嘛
_asm
{
lea eax,MyMessageBoxW //获取我们的MyMessageBoxW函数地址
mov ebx,pfOldMsgBoxW //原系统API函数地址
sub eax,ebx //int nAddr= UserFunAddr –SysFunAddr
sub eax, //nAddr=nAddr-5
mov dword ptr [NewCode+],eax //将算出的地址nAddr保存到NewCode后面个字节
//注:一个函数地址占个字节
} //填充完毕,现在NewCode[]里的指令相当于Jmp MyMessageBoxW
//既然已经获取到了Jmp MyMessageBoxW
//现在该是将Jmp MyMessageBoxW写入原API入口前个字节的时候了
//知道为什么是个字节吗?
//Jmp指令相当于xe9,占一个字节的内存空间
//MyMessageBoxW是一个地址,其实是一个整数,占个字节的内存空间
//int n=0x123; n占个字节和MyMessageBoxW占个字节是一样的
//1+4=5,知道为什么是个字节了吧
HookOn();
} BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
DWORD dwPid=::GetCurrentProcessId();
hProcess=OpenProcess(PROCESS_ALL_ACCESS,,dwPid);
GetApiEntrance();
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
HookOff();
break;
}
return TRUE;
}

其中:

DWORD dwPid=::GetCurrentProcessId();

hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

这两行的作用是得到被注入DLL进程的进程句柄。

好了DLL库部分已经解决,那让我看看远程注入DLL到指定进程部分的代码吧。

在开始之前最好将DLL先编译出来,以便在下面的代码中使用。

我创建的win32控制台应用程序来测试。

直接上代码:)。

 // exe.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <time.h> BOOL InjectDllToRemoteProcess(const char* lpDllName, const char* lpPid, const char* lpProcName); int main(int argc, char* argv[])
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si,,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_SHOW;
si.dwFlags=STARTF_USESHOWWINDOW;
BOOL fRet=CreateProcess(_T("C:\\Users\\Administrator\\Desktop\\远程进程注入与HOOKapi例子\\exe\\ASD.exe"),NULL,NULL,FALSE ,NULL,NULL,NULL,NULL,&si,&pi);
//创建一个进程,这个进程可以是你自己写的MFC程序。 if (!fRet)
{
//创建进程失败
MessageBoxW(NULL,L"创建进程失败",L"error",MB_OK); } BOOL isInject = InjectDllToRemoteProcess("C:\\Users\\Administrator\\Desktop\\远程进程注入与HOOKapi例子\\exe\\MyDLL.dll", NULL , "ASD.exe");
// C:\\Users\\Administrator\\Desktop\\远程进程注入与HOOKapi例子\\exe\\MyDLL.dll这个的DLL的路径
// ASD.exe是要注入的进程名,可以写一个MFC对话框程序在上面添加个按钮点击按钮弹出MessageBox看看你的MessageBox是不是被HOOK住了 if (!isInject)
{
//注入远程进程失败
MessageBoxW(NULL,L"注入远程进程失败",L"error",MB_OK);
} while()
{ } return ;
}
//进程快照(枚举各进程)
BOOL GetPidByProcessName(LPCTSTR lpszProcessName , DWORD &dwPid)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, );
if ( INVALID_HANDLE_VALUE == hSnapshot )
{
return FALSE;
} PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if ( !Process32First(hSnapshot, &pe) )
{
::CloseHandle(hSnapshot);
return FALSE;
} while ( Process32Next(hSnapshot, &pe) )
{
if ( !_stricmp(lpszProcessName, pe.szExeFile) )
{
::CloseHandle(hSnapshot);
dwPid = pe.th32ProcessID;
return TRUE;
}
} ::CloseHandle(hSnapshot);
return FALSE;
} /********************************************************************************************************/ //注入DLL到远程进程
BOOL InjectDllToRemoteProcess(const char* lpDllName, const char* lpPid, const char* lpProcName)
{
DWORD dwPid = ;
if (NULL == lpPid || == strlen(lpPid))
{
if (NULL != lpProcName && != strlen(lpProcName))
{
if (!GetPidByProcessName(lpProcName, dwPid))
{
return FALSE;
}
}
else
{
return FALSE;
}
}
else
{
dwPid = atoi(lpPid);
} //根据Pid得到进程句柄(注意必须权限)
HANDLE hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, dwPid);
if (INVALID_HANDLE_VALUE == hRemoteProcess)
{
return FALSE;
} //计算DLL路径名需要的内存空间
DWORD dwSize = ( + lstrlenA(lpDllName)) * sizeof(char); //使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲区,成功返回分配内存的首地址.
LPVOID lpRemoteBuff = (char *)VirtualAllocEx(hRemoteProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (NULL == lpRemoteBuff)
{
CloseHandle(hRemoteProcess);
return FALSE;
} //使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间,成功返回TRUE.
DWORD dwHasWrite = ;
BOOL bRet = WriteProcessMemory(hRemoteProcess, lpRemoteBuff, lpDllName, dwSize, &dwHasWrite);
if (!bRet || dwHasWrite != dwSize)
{
VirtualFreeEx(hRemoteProcess, lpRemoteBuff, dwSize, MEM_COMMIT);
CloseHandle(hRemoteProcess);
return FALSE;
} //创建一个在其它进程地址空间中运行的线程(也称:创建远程线程),成功返回新线程句柄.
//注意:进程句柄必须具备PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE,和PROCESS_VM_READ访问权限
DWORD dwRemoteThread = ;
//LPTHREAD_START_ROUTINE pfnLoadLibrary = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");
//HANDLE hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, 0, pfnLoadLibrary, lpRemoteBuff, 0, &dwRemoteThread);
HANDLE hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, , (LPTHREAD_START_ROUTINE)LoadLibraryA, lpRemoteBuff, , &dwRemoteThread);
if (INVALID_HANDLE_VALUE == hRemoteThread)
{
VirtualFreeEx(hRemoteProcess, lpRemoteBuff, dwSize, MEM_COMMIT);
CloseHandle(hRemoteProcess);
return FALSE;
} //注入成功释放句柄
WaitForSingleObject(hRemoteThread, INFINITE);
CloseHandle(hRemoteThread);
CloseHandle(hRemoteProcess); //补充:卸载过程(有bug)
//准备卸载之前注入的Dll
//DWORD dwHandle, dwID;
//LPVOID pFunc = GetModuleHandleA; //获得在远程线程中被注入的Dll的句柄
//HANDLE hThread = CreateRemoteThread(hRemoteProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpRemoteBuff, 0, &dwID);
//WaitForSingleObject(hThread, INFINITE);
//GetExitCodeThread(hThread, &dwHandle); //线程的结束码即为Dll模块儿的句柄
//CloseHandle(hThread);
//pFunc = FreeLibrary;
//hThread = CreateRemoteThread(hThread, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, (LPVOID)dwHandle, 0, &dwID); //将FreeLibraryA注入到远程线程中去卸载Dll
//WaitForSingleObject(hThread, INFINITE);
//CloseHandle(hThread);
//CloseHandle(hRemoteProcess); return TRUE;
}

代码的注释还是很清楚的,就不解释了。

使用VC++通过远程进程注入来实现HOOK指定进程的某个API的更多相关文章

  1. 安全之路 —— 借助DLL进行远程线程注入实现穿墙与隐藏进程

    简介        大多数后门或病毒要想初步实现隐藏进程,即不被像任务管理器这样典型的RING3级进程管理器找到过于明显的不明进程,其中比较著名的方法就是通过远程线程注入的方法注入将恶意进程的DLL文 ...

  2. CreateRemoteThread远程线程注入Dll与Hook

    CreateRemoteThread虽然很容易被检测到,但是在有些场合还是挺有用的.每次想用的时候总想着去找以前的代码,现在在这里记录一下. CreateRemoteThread远程注入 DWORD ...

  3. C#EasyHook例子C# Hook 指定进程C#注入指定进程 z

    http://bbs.msdn5.com/thread-75-1-1.html http://pan.baidu.com/s/1pJDgHcR

  4. 利用 ps 怎么显示所有的进程? 怎么利用 ps 查看指定进程的信息?

    ps -ef (system v 输出)ps -aux bsd 格式输出ps -ef | grep pid

  5. Wow64(32位进程)注入DLL到64位进程

    转载自: https://blog.poxiao.me/p/wow64-process-inject-dll-into-x64-process/ 向其他进程注入DLL通常的做法是通过调用CreateR ...

  6. 详细解读:远程线程注入DLL到PC版微信

    一.远程线程注入的原理 1.其基础是在 Windows 系统中,每个 .exe 文件在双击打开时都会加载 kernel32.dll 这个系统模块,该模块中有一个 LoadLibrary() 函数,可以 ...

  7. 进程注入后门工具Cymothoa

    进程注入后门工具Cymothoa   Cymothoa是一款隐秘的后门工具.它通过向目标主机活跃的进程注入恶意代码,从而获取和原进程相同的权限.该工具最大的优点就是不创建新的进程,不容易被发现.由于该 ...

  8. EasyHook远程进程注入并hook api的实现

    EasyHook远程进程注入并hook api的实现 http://blog.csdn.net/v6543210/article/details/44276155

  9. 安全之路 —— 无DLL文件实现远程进程注入

    简介 在之前的章节中,笔者曾介绍过有关于远程线程注入的知识,将后门.dll文件注入explorer.exe中实现绕过防火墙反弹后门.但一个.exe文件总要在注入时捎上一个.dll文件着实是怪麻烦的,那 ...

随机推荐

  1. TransactionScope使用说明 【转】

    TransactionScope是.Net Framework 2.0滞后,新增了一个名称空间.它的用途是为数据库访问提供了一个“轻量级”[区别于:SqlTransaction]的事物.使用之前必须添 ...

  2. activity-alias的使用

    activity-alias是android里为了反复使用Activity而设计的. 当在Activity的onCreate()方法里,运行getIntent().getComponent().get ...

  3. ParNew收集器

    ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数,其中Par是Paralle简写l 并行(Parallel) ...

  4. [jQuery]无法获取隐藏元素(display:none)宽度(width)和高度(height)的新解决方案

    在做茶城网改版工作的时候,又遇到一个新问题,我需要用jQuery写一个通过点击左右图标来翻阅图片的小插件,写好后测试可以正常运行,但是放到Tab中后发现只有第一个Tab中的代码能够正常运行,其它全部罢 ...

  5. 为什么Underscore

    Underscore是什么? Underscore一个JavaScript实用库,提供了一整套函数式编程的实用功能,但是没有扩展任何JavaScript内置对象.它是这个问题的答案:“如果我在一个空白 ...

  6. UIButton 头文件常见属性和方法

    UIButton头文件常见属性 1.属性 contentEdgeInsets: default is UIEdgeInsetsZero.设置内容四边距,默认边距为0 @property(nonatom ...

  7. codevs1304 拓扑序计数

    题目描述                     Description 求一颗有根树/树形图的拓扑序个数. 输入描述                 Input Description        ...

  8. C++命名准则

    总则:命名用英语,单词简单,明了.意义明确.过长的单词可以使用省略.一般是去掉元音字母形成省略.如果有通用的缩写,应该采用通用的缩写. 1.函数命名 1.1:全局函数:采用限定词+动词(+名词的原则) ...

  9. Linux编程C/C++

    C/C++基本数据类型 C/C++语言有一组基本数据类型,对应于计算机的基本存储单元和使用这些单元去保存数据的一些常用方式. 基本数据类型如下: 上面表格中的类型是基本的C/C++数据类型,但是在C+ ...

  10. 十个最值得阅读学习的C开源项目代码

    1. Webbench Webbench 是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能,最多可以 模拟3万个并 ...