草庐IT

PC微信hook基础框架代码编写-->获取微信日志

张国五 2023-07-25 原文

PC微信hook基础框架代码编写-->获取微信日志

一、 封装微信hook框架和一些基本功能

首先我们搭建好一个基础的hook框架

1. 新建一个dll工程

2. 新建一个CHook类 并编写对应的函数

CHook类封装两个函数
1.hook任意地址
2.获取基地址
Hook.h 代码如下

#pragma once
class CHook
{
public:
	CHook(); //构造函数
	~CHook(); //析构函数
public:
	void HookAnyAddress(DWORD dwHookAddress, LPVOID jmpAddress);//HOOK 任意地址
	DWORD GetWechatWinBase(); //获取基地址
};

*Hook.cpp 代码如下

#include "pch.h"
#include "Hook.h"

CHook::CHook()
{

}
CHook::~CHook()
{

}


//************************************
// 函数名称: HookAnyAddress
// 函数说明: Hook 任意地址
// 作者名称: 张国五
// 返回  值: void
// 传入参数: 要hook的地址
// 传入参数: 要跳转回的地址
//************************************
void CHook::HookAnyAddress(DWORD dwHookAddress, LPVOID jmpAddress)
{
	//组装跳转数据
	BYTE jmpCode[5] = { 0 };
	jmpCode[0] = 0xE9;

	//计算偏移
	*(DWORD*)&jmpCode[1] = (DWORD)jmpAddress - dwHookAddress - 5;

	//保存以前属性用于还原
	DWORD oldProperty = 0;

	// 因为要往代码段写入数据,又因为代码段是不可写的,所以需要修改属性
	VirtualProtect((LPVOID)dwHookAddress, 5, PAGE_EXECUTE_READWRITE, &oldProperty);

	//写入自己的代码
	memcpy((void*)dwHookAddress, jmpCode, 5);

	// 执行完了操作之后需要进行还原
	VirtualProtect((LPVOID)dwHookAddress, 5, oldProperty, &oldProperty);
}

//************************************
// 函数名称: GetWechatWinBase
// 函数说明: 获取基地址
// 作者名称: 张国五
// 返回  值: 基地址
//************************************
DWORD CHook::GetWechatWinBase()
{
	return (DWORD)GetModuleHandleA("WechatWin.dll");
}

3. 新建一个CTools工具类 封装一下日志输出

CTools 封装两个函数
1.输出ascII码 窄字符 日志消息
2.输出unicode 宽字符日志消息
Tools.h代码如下

#pragma once
class CTools
{
public:
	CTools(); //构造函数
	~CTools(); //析构函数
public:
	void OutPutLogA(char* lpcszOutputString, ...); //输出ascII码 窄字符 日志消息
	void OutPutLogW(wchar_t* lpcwszOutputString, ...); //输出unicode 宽字符日志消息
};


Tools.cpp代码如下

#include "pch.h"
#include "Tools.h"
#include <vector>

CTools::CTools()
{

}

CTools::~CTools()
{

}

//************************************
// 函数名称: OutPutLogA
// 函数说明: 输出A版本日志
// 作者名称: 张国五
// 返回  值: void
// 传入参数: const char * lpcszOutputString
// 传入参数: ...
//************************************
void CTools::OutPutLogA(char* lpcszOutputString, ...)
{
	if (NULL == lpcszOutputString)
	{
		return;
	}
	char* strResult = nullptr;
	va_list marker = NULL;
	va_start(marker, lpcszOutputString); //初始化变量参数
	size_t nLength = _vscprintf(lpcszOutputString, marker) + 1; //获取格式化字符串长度
	std::vector<char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
	int nWritten = _vsnprintf_s(&vBuffer[0], vBuffer.size(), nLength, lpcszOutputString, marker);
	if (nWritten < 0)
	{
		return;
	}
	strResult = &vBuffer[0];
	va_end(marker); //重置变量参数
	if (strResult == nullptr)
	{
		return;
	}
	char buff[0x1024] = { 0 };
	memset(buff, 0, sizeof(buff));
	char* strFormated = (char*)"[WechatLogs:] "; //识别符 判断是否是自己的日志
	strcpy_s(buff, strFormated);   //拼接
	strcat_s(buff, strResult);
	OutputDebugStringA(buff);
}

//************************************
// 函数名称: OutPutLogW
// 函数说明: 输出W版本日志
// 作者名称: 张国五
// 返回  值: void
// 传入参数: const wchar_t * lpcwszOutputString
// 传入参数: ...
//************************************
void CTools::OutPutLogW(wchar_t* lpcwszOutputString, ...)
{
	wchar_t* strResult = nullptr;
	if (NULL == lpcwszOutputString)
	{
		return;
	}
	va_list marker = NULL;
	va_start(marker, lpcwszOutputString); //初始化变量参数
	size_t nLength = _vscwprintf(lpcwszOutputString, marker) + 1; //获取格式化字符串长度
	std::vector<wchar_t> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
	int nWritten = _vsnwprintf_s(&vBuffer[0], vBuffer.size(), nLength, lpcwszOutputString, marker);
	if (nWritten <0)
	{
		return;
	}
	strResult = &vBuffer[0];
	va_end(marker); //重置变量参数
	if (strResult == nullptr)
	{
		return;
	}
	wchar_t buff[0x2048] = { 0 };
	wchar_t* strFormated = (wchar_t*)L"[WechatLogs:] ";
	wcscpy_s(buff, strFormated);
	wcscat_s(buff, strResult);
	OutputDebugStringW(buff);
}

二、 hook微信日志

这里我们开始hook微信的日志,在编写此代码前 请先阅读我这篇文章:
https://blog.csdn.net/tuoguochen/article/details/127666928?spm=1001.2014.3001.5502

1. 新建一个CWechatLogs类 hook并输出日志

CWechatLogs
CWeChatLogs.h代码如下

#pragma once
#include "Hook.h"
#include "Tools.h"

class CWeChatLogs :CHook //继承hook类

{
public:
	CWeChatLogs();  //构造函数
	~CWeChatLogs(); //析构函数

public:
	void                       HookGetWeChatLogs();  //获取微信日志消息
	static void __stdcall             WeChatLogsCore(DWORD CodePath, DWORD MMPCName, DWORD FunName, DWORD LogMessage); //输出日志消息
	

};


CWechatLogs.cpp代码如下

#include "pch.h"
#include "WeChatLogs.h"
#include "OffSet.h"
CTools             m_pTools; 
DWORD              JmpLogAddr; 
CWeChatLogs::CWeChatLogs()
{
	
}

CWeChatLogs::~CWeChatLogs()
{
	
}
//************************************
// 函数名称: GetLogs
// 函数说明: 裸函数
// 作者名称: 张国五
// 返回  值: void
//************************************
__declspec(naked) void GetLogs()
{
	//内联汇编 取了重要的地方 其他需要可以自己取出
	__asm
	{
		pushad;  //将所有寄存器状态压入堆栈
		mov eax, [esp + 0x18 + 0x20]; //从堆栈中拿出数据  因为8个寄存器被压入堆栈  每个寄存器 8个byte 四个字节 所以 +0x20
		push eax;
		mov ebx, [esp + 0x24 + 0x20 + 0x4]; //压入eax 所以 +0x4
		push ebx;
		mov ecx, [esp + 0x2c + 0x20 + 0x8];
		push ecx;
		mov edx, [esp + 0x70 + 0x20 + 0xc];
		push edx;
		call CWeChatLogs::WeChatLogsCore; //调用自己的函数  恢复堆栈 取出数据
		popad;  //恢复寄存器
		lea eax, dword ptr ss : [esp + 0x20]; //恢复代码
		push esi;   //恢复代码
		jmp JmpLogAddr; //跳转回去
	}
}

//************************************
// 函数名称: HookGetWeChatLogs
// 函数说明: hook日志
// 作者名称: 张国五
// 返回  值: void
//************************************
void CWeChatLogs::HookGetWeChatLogs()
{
	//要跳转回去的地址
	JmpLogAddr = GetWechatWinBase() + WxHookGetLog + 5;
	//hook 挂钩子
	HookAnyAddress(GetWechatWinBase() + WxHookGetLog, GetLogs);
	

}

//************************************
// 函数名称: GetWeChatLogsCore
// 函数说明:
// 作者名称: 张国五
// 返回  值: void __stdcall
// 传入参数: DWORD CodePath
// 传入参数: DWORD MMPCName
// 传入参数: DWORD FunName
// 传入参数: DWORD LogMessage
//************************************
void __stdcall CWeChatLogs::WeChatLogsCore(DWORD LogMessage, DWORD FunName, DWORD MMPCName, DWORD CodePath)
{
	//输出日志
	m_pTools.OutPutLogA((char*)"-------------------------------------------------------");
	m_pTools.OutPutLogA((char*)"%s\r\n", (char*)FunName);
	m_pTools.OutPutLogA((char*)"%s\r\n", (char*)MMPCName);
	m_pTools.OutPutLogA((char*)"%s", (char*)CodePath);
	m_pTools.OutPutLogA((char*)"%s\r\n", (char*)LogMessage); //logmessage自带 \n 为了日志美观 所以放到最后
}

三、 调用和注入

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "WeChatLogs.h"
//hook日志对象
CWeChatLogs* pWeCahtLogs  = new CWeChatLogs;

//DLL启动入口
//************************************
// 函数名称: DllMain
// 函数说明: 临时测试 简单在这里调用一下
// 作者名称: 张国五
// 返回  值: BOOL APIENTRY
// 传入参数: HMODULE hModule
// 传入参数: DWORD ul_reason_for_call
// 传入参数: LPVOID lpReserved
//************************************
BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call, LPVOID lpReserved)
{
	
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
		OutputDebugStringA("开始注入");
		pWeCahtLogs->HookGetWeChatLogs();
		if (pWeCahtLogs != NULL)
		{
			delete pWeCahtLogs;
			pWeCahtLogs = NULL;
		}
		OutputDebugStringA("注入完成");
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
	
    return TRUE;
}


注入代码可以自行编写 也可以使用ollydbg注入到微信的进程

四、 整个工程结构

五、 测试效果图

有关PC微信hook基础框架代码编写-->获取微信日志的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  4. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  5. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  6. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  7. ruby - 从 Ruby 中的主机名获取 IP 地址 - 2

    我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge

  8. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  9. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  10. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

随机推荐