支持HW团队,就支付宝领取下面的红包吧! (打开支付宝就能领取!er1OEj73Uj), (打开支付宝收索“516503473”), 你领取消费,HW有奖励。红包使用无条件限制,有条件请注意是不是有病毒。

Login or Sign up | Validate
| Search
HelloWorld论坛 : > 计算机科学、技术、教学> 编程入门> c、c++基础> 【转】微信Hook实战记录2:动手实现恶意dll内存插入器
 
 
 
 
类别:其他 阅读:559 评论:0 时间:April 1, 2020, 9 p.m. 关键字:微信Hook实战记录

 

 来源:https://blog.csdn.net/weixin_30230009/article/details/105100172

Hook任何软件,整体思路都是通过内存调试软件对软件运行时内存进行断点调试,找到想要hook的内存地址,转为可以通过程序主dll可以获得的相对地址,然后再此处插入自己的恶意汇编代码,如果代码比较复杂,还需要编写寄存器保护逻辑,避免自己的恶意代码修改了寄存器中的值后,程序正常的逻辑无法运行。

前言

在上一篇文章「微信Hook实战记录 1:找到个人信息」中,介绍了如何使用OD与CE来找到微信中存放个人信息的内存位置,本篇文章尝试通过C++编写一个简单的内存注入工具,将我们自己的恶意dll注入到微信的内存中。

本文记录了大量细节,完全可以模仿复现相同的效果。

内存注入工具的编写

打开 Visual Studio 2019(下载的时候勾选 C++ 桌面支持,6.9G左右),选择创建新项目

选择创建 Windows 桌面向导

然后创建就可以了,这里创面项目名为 Project1

创建完后,VS 会为我们创建一个默认的界面,我们在 解决方案 -> 源文件 中找到 Project1.cpp,这个文件就是我们要写逻辑的主要界面

将其中多余的代码删除,就留下如下代码

// Project1.cpp : 定义应用程序的入口点。 // #include "framework.h" #include "Project1.h" int APIENTRY wWinMain(_In_ HINSTANCE hInstance,     _In_opt_ HINSTANCE hPrevInstance,     _In_ LPWSTR    lpCmdLine,     _In_ int       nCmdShow) {     return 0; } 

wWinMain 是界面程序的入口,所有不必删除

接着将 解决方案 --> 资源文件 中的内容删除,这是 VS 默认创建好的,删除后,自己新建一个资源文件

选择 Dialog,即弹出框

调整一下创建出的按钮位置以及整体大小

要设置按钮与整体的属性,如按钮要设置其内容与ID,而整体Dialog也要设置一下其ID,可以右键点击 --> 属性

其他控制以相同的方式去设置,设置后后,就可以写代码了

首先修改一下 Project1.h 中的内容,如下

#pragma once #include "resource1.h" 

具体内容要看你VS为你生成了什么,前面我们通过图像界面操作后,VS会生成的相应的头文件,这里我生成了 resource1.h 的头文件,其内容如下:

//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Project1.rc 使用 // #define ID_MAIN                         101 #define UN_DLL                          1001 #define INJECT_DLL                      1002 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE        103 #define _APS_NEXT_COMMAND_VALUE         40001 #define _APS_NEXT_CONTROL_VALUE         1003 #define _APS_NEXT_SYMED_VALUE           101 #endif #endif #endif 

可以看出,其实就是我们设置的ID等内容

接着来修改一下 Project1.cpp, 其 wWinMain 方法修改如下:

#include "framework.h" #include "Project1.h" #include <TlHelp32.h>   #include <stdio.h> // 微信进程名 #define WECHAT_PROCESS_NAME "WeChat.exe" int APIENTRY wWinMain(_In_ HINSTANCE hInstance,     _In_opt_ HINSTANCE hPrevInstance,     _In_ LPWSTR    lpCmdLine,     _In_ int       nCmdShow) {     // hInstance 将句柄传递给弹窗     // 传入 Dialgo 主体ID     // DialogProc 回调函数,是一个指针,即该函数的地址     DialogBox(hInstance, MAKEINTRESOURCE(ID_MAIN), NULL, &DialogProc);     return 0; } 

因为创建的资源是 Dialog ,所以这里通过 DialogBox 来使用它,它在 Windows.h 的头文件中,如果你使用的 VS 2019,其 framework.h 文件就包含Windows.h了。

DialogBox的参数可以通过微软的文档来查看

void DialogBoxA(    hInstance,    lpTemplate,    hWndParent,    lpDialogFunc ); 

hInstance,类型:HINSTANCE,包含对话框模板的模块句柄。如果此参数为 NULL,则使用当前可执行文件。lpTemplate,类型:LPCTSTR,对话框模板。可以使用MAKEINTRESOURCE宏来创建此值。hWndParent,类型:HWND,拥有该对话框的窗口的句柄。lpDialogFunc,类型:DLGPROC,指向对话框过程的指针。

根据文档提示,完成代码

#include "framework.h" #include "Project1.h" #include <TlHelp32.h>   #include <stdio.h> #define WECHAT_PROCESS_NAME "WeChat.exe" // 注册函数,方便其他模块使用 INT_PTR CALLBACK DialogProc(_In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam); VOID InjectDll(); int APIENTRY wWinMain(_In_ HINSTANCE hInstance,     _In_opt_ HINSTANCE hPrevInstance,     _In_ LPWSTR    lpCmdLine,     _In_ int       nCmdShow) {     DialogBox(hInstance, MAKEINTRESOURCE(ID_MAIN), NULL, &DialogProc);     return 0; } INT_PTR CALLBACK DialogProc(_In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam) {     if (uMsg == WM_INITDIALOG) {         MessageBox(NULL, "首次加载", "标题", 0);     }     // 关闭界面操作     if (uMsg == WM_CLOSE) {         EndDialog(hwndDlg, 0);     }     // 所有的界面上的按钮事件都会走这个宏     if (uMsg == WM_COMMAND) {         if (wParam == INJECT_DLL) {             InjectDll(); //注入 Dll         }         if (wParam == UN_DLL) {         }     }     return FALSE; } 

接着来实现 InjectDll() 方法,完成注入 DLL 的功能,整体分 3 步走。

1.获取微信的PID,通过PID获得微信进程的句柄,从而拥有了权限 2.申请内存,内存大小为 DLL 路径大小 3.将 DLL 路径注入到微信进程中

DWORD ProcessNameFindPID(LPCSTR ProcessName) {     // #include <TlHelp32.h>     // 获取进程快照     HANDLE ProcessAll = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);// 获取整个系统的进程快照     // 在快照中对比过 processname 进程名称     PROCESSENTRY32 processInfo = { 0 };     processInfo.dwSize = sizeof(PROCESSENTRY32);     do     {         // WeChat.exe         // th32ProcessID 进程ID, szExeFile进程名         if (strcmp(ProcessName, (char*)processInfo.szExeFile) == 0) {             return processInfo.th32ProcessID;         }     } while (Process32Next(ProcessAll, &processInfo));     return 0; } 

上述方法,需要 windows 平台 C++ 基础。其实主要就是对 Windows.h 中方法的调用,接着完成如下效果

VOID InjectDll() {   // 自己恶意dll的路径     CHAR pathStr[0x100] = { "D://GetWeChatInfo.dll" };     // 获取微信PID     DWORD PID = ProcessNameFindPID(WECHAT_PROCESS_NAME);     if (PID == 0) {         MessageBox(NULL, "没有找到微信进程或微信没有启动", "错误", 0);         return;     }     // 通过PID获取句柄 C++中句柄类型为 HANDLE     HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);     if (NULL == hProcess) {         MessageBox(NULL, "进程打开失败,可能权限不足或关闭了微信应用", "错误", 0);         return;     }     //申请内存,内存大小为我们要注入 DLL 的大小     LPVOID dllAdd = VirtualAllocEx(hProcess, NULL, sizeof(pathStr), MEM_COMMIT, PAGE_READWRITE);     if (NULL == dllAdd) {         MessageBox(NULL, "内存分配失败", "错误", 0);         return;     }     // 将 DLL 写入到对应的内存地址中     if(WriteProcessMemory(hProcess, dllAdd, pathStr, strlen(pathStr), NULL) == 0) {         MessageBox(NULL, "路径写入失败", "错误", 0);         return;     }     // 创建一块内存用来打印一段文本,方便看效果     CHAR test[0x100] = { 0 };     sprintf_s(test, "写入的地址为:%p", dllAdd);     OutputDebugString(test); } 

完成后,直接编译运行,如果编译后的效果依旧是之前代码的效果,你可以 重新生成解决方案,然后再编译。

点击注入,获得注入的位置,通过 Cheat Engine 来查看该位置的内容

通过CE查看相应的内存地址,发现该内存地址为dll的路径,注入dll成功

注入成功后,还需要调用 Kernel32.dll 中的方法,调用该路径下的 dll 就完成 dll的注入了,代码如下:

  // 省略显示前面的代码   // 创建一块内存用来打印一段文本,方便看效果     CHAR test[0x100] = { 0 };     sprintf_s(test, "写入的地址为:%p", dllAdd);     OutputDebugString(test);     //将地址写入后,通过 Kernel32.dll 调用该地址的 DLL 就完成了     HMODULE k32 = GetModuleHandle("Kernel32.dll");     LPVOID loadAdd = GetProcAddress(k32, "LoadLibraryA");     // 远程执行我们的dll,通过注入的dll地址以及CreateRemoteThread方法让微信进程调用起我们的进程     HANDLE exec = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadAdd, dllAdd, 0, NULL);     if (exec == NULL) {         MessageBox(NULL, "远程注入失败", "错误", 0);         return;     } 

此时 DLL 就相当于在微信进程中了。

DLL中的函数就可以操作微信进程中的内存了,从而实现获取微信信息的目的。

如果没有调用其DLL,则需要注意一下 LoadLibraryA 方法,该方法会调用 ASCII的路径地址,如果你是unicode的话,则需要调用 LoadLibraryW 方法,如果不成功,可以尝试替换一下。

没有Windows平台开发C++的朋友看完上面代码可能会感到疑惑,为什么将恶意dll路径插入内存后,可以让微信进程自己去载入这个恶意dll呢?

简单解释一下,在windows中,每个进程在启动时都会载入Kernel32.dll,微信进程会载入Kernel32.dll,浏览器进程也会载入Kernel32.dll,而我们可以通过Kernel32.dll中的LoadLibraryA()方法或LoadLibraryW()方法去动态载入新的dll,需要解释一下,我们在自己的进程中获取LoadLibraryA()方法的内存位置,这个内存位置对windows中其他进程而言是相同的。

但关键点是通过微信进程去使用Kernel32.dll中的LoadLibraryA()方法载入新的dll,为了实现这个目的,就需要使用CreateRemoteThread()方法,该方法可以远程调用其他进程的中的方法,前提是要有该进程的句柄(即执行权限),而我们在一开始就获得了微信进程的执行权限。

总结一下整个流程:

  • 1.将恶意dll路径插入到微信进程运行内存中

  • 2.获取当前进程(我们自己的进程,而非微信进程)Kernel32.dll中LoadLibraryA()方法或LoadLibraryW()方法,因为微信进程也载入了Kernel32.dll,所以微信进程可以在相同的内存地址处找到LoadLibraryA()方法或LoadLibraryW()方法

  • 3.通过CreateRemoteThread()方法,让微信进程去调用LoadLibraryA()方法载入恶意dll

结尾

本文并没有给出恶意dll的具体实现逻辑,后面将实现一个简单的dll,来获取微信的个人信息,其实基于上一篇文章,找到了个人信息的具体内存位置,该dll要做的只是从中读取信息,仅此而已。

但恶意dll还可以实现很多复杂的功能,比如监控聊天信息、自动收红包、自动踢人等各种功能,这些功能在后面有机会再分享给大家。

 
相关博文 首页 上页 1 2 下页 尾页 共2条
[审核人]初学MPEG

个人签名--------------------------------------------------------------------------------

Please Login (or Sign Up) to leave a comment