逆向WeChat(四)

wechat · 浏览次数 : 0

小编点评

**核心的network模块** * **comm**目录:封装了网络通信相关的API和数据结构,如socket、buffer等。 * **thread**目录:处理线程的接口,如RunLoop、Condition等。 * **messagequeue**目录:处理消息队列,包含发送和接收消息的接口和线程。 ** messagequeue的设计** * 每个线程对应一个消息队列,队列ID作为线程ID。 * 消息队列由MessageHandler处理,通过投递消息的方式进行处理。 * 在Java中,Handler使用`post()`和`send()`方法实现消息传递。 **其他相关目录** * **RunLoop**:用于创建和管理RunLoop的类。 * **Breadker**:用于创建Condition的类,提供同步机制。 * **Task**:用于管理异步任务的接口,包含start、join等方法。 **应用层接口** * **StnManagerShortLinkLongLinkShortLinkManagerLongLinkManager**:提供接口用于管理短链和长链消息队列。 * **Stn**:封装了所有模块的接口,包含逻辑、manager、core等部分。 **问题** * 因为每个线程对应一个消息队列,而每个消息队列可能由多个线程发送消息,如何确保线程安全? * 为什么要使用`any_cast()`进行类型转换?

正文

本篇在博客园地址https://www.cnblogs.com/bbqzsl/p/18209439

mars

先回顾一下,在上两篇《WeUIEngine》《EventCenter》。我对wechat如何使用chrome::base框架的分析中需要更正补充。首先要指出,逆向分析是一个过程。需要经过不断假设,推断,求证,验证。花费时间一步一步将结果改进完善的循序渐进的过程。当前的内容只代表当前分析的过程跟结果,当前的分析是以当前局限的结果作为前提的。还在逆向分析初期,我只运行少量功能场景,忽略了TaskScheduler除了Pump外。还有就是wechat在初始化时,已经将主线程的TaskRunner保存到了全局变量,用作主线程的dispatch_main_queue,供全局使用。但是EventCenter仍然是中心。

回到本篇内容,mars。

在逆向分析,我发现了StartTask的实际代码,将stn::Task进行了十次copy构造。一个320字节的结构,有10多个string,几个vector<string>,一个map<string,string>。佐证在本篇后面。

作为network模块,先来看SocketSelect。windows基于WASSelect,macos基于kevent,linux android它也看作unix,这个有点偷懒。对于看热闹的人来说linux是类unix系统,但是对于unix系统使用者就不买这个帐,unix跟linux就是两个东西。macos是基于freebsd,是unix分支,内核用kqueue,macos的MachPort就是基于kqueue。linux有它独用的epoll,好像也始于2.6内核的时代,内核并没kqueue。mars在非macos的系统中通通由poll来解决。这不是问题的关键。因为每一个tcp连接开一个线程,没有事件分离器复用。我也是惊了个呆。难怪低配置的安卓手机直接用不起,记得N年前28nm的晓龙425还可以运行微信6,微信7后因为旧版登陆接口不支持,强制升级微信后只能卡死在登陆进行转进入主界面。一个28nm的4cores1.4g的旧cpu且只带2GB运存的破手机,在2024年还可以运行最新版淘宝,大部分功能。不知道这东西,是不是如项目描述那样,在它自家的产品中跨平台使用了。freebsd,darwin-xnu,linux-kernel在github都有源代码。

window需要vc2015,那么姑且需要c++14,clang3.4于2013年就支持了,xcode跟ndk同样适用。c++14已经有不少boost库的东西,而且lambda也很成熟了。用boost::bind看着真的头晕。年轻时我也曾非boost不够cool。boost::bind(method, this, _1, _2, _3, _4, _5, _6),用python言语就是lambda a,b,c,d,e,f: this.method(a, b, c, d, e, f),用c++11的lambda就是[=](auto& a, auto& b, auto& c, auto& d, auto& e, auto& f) { return this->method(a, b, c, d, e, f); },以及std::function<auto(, , , , , , )>。boost::bind也就等同lambda的一种实现方式。调试有boost的项目时有个无尽长的名字我却不知道你是什么的恶梦。  

在mars的设计中,mars既是namespace也是目录,mars下一级就是子模块,同样既是namespace也是目录,如mars::comm,mars::sdt,mars::stn。这里不能不说是在参考了java的包层级。

stn,我认为就是简单的首字命名,Strategy,Task,Network。重点就是network,这是一个network模块。至于Strategy就简单理解成ShortLink,LongLink。Task,原本咋一看还以为comm::mq分派Task,这个stn是一个分派中心,包括Task还有socket操作,Strategy类似于scheduler。实质却不是这样。Task就是在一个ShortLink或LongLink上完成一轮Request-Response。这个Task的设计就类似于js的XMLHttpRequest。js中,xhr = new XMLHttpRequest; xhr.onreadystatechange= function() {} ; xhr.open(); xhr.send(request_packet)。再来看mars,tsk = new Task(request_packet); tsk.OnEndTask = lambda; mars::stn::StartTask(tsk); 同一配方。所以我认为stn就是mars核心的network模块。

至于comm目录下的东西。socket跟network子目录只是些底层socket相关的api跟数据结构的封装,Facade模式。thread子目录转到平台对应的子目录。也是同步,TSS等相关的Facade封装。messagequeue子目录,我原来以为会是mars的重要的东西,跟它的线程模型会的密切关联。这个messagequeue的设计,就是在模仿Java的RunLoop。概念是一个线程对应一个messagequeue,线程id作为队列id。由绑定的MessageHandler处理message,只能用MessageHandler投递消息。在java中,handler = new Handler(Loop()); handler.SendMessage();handler.post();。回到mars上。messagequeue必须加上一个RunLoop构成一个Pump在线程中pump。MessageQueueCreater是一个自带线程以及Pump的类,它存在于stn::NetCore,comm::GetDefMessageQueue,还有comm::GetDefTaskQueue。如果你没有InstanllAsyncHandler去安装一个MessageHandler专门将message作为runnable处理,就是有Pump在线程运行也不分派runnable。几乎stn内每个功能类都有一个默认到comm::GetDefMessageQueue的MessageHandler,用来进行AsyncInvoke,但又似乎stn都基本上没有怎么用。(分别只这几处使用:Alarm.cc, BroadcastMessage。signalling_keeper.cc, AsyncInvokeAfter。zombi_task_manager.cc SingletonMessage。netsource_timechecker.cc, AsyncInvokePeriod。ActiveLogic::OnForeground,  AsyncInvoke。)。并非,comm::mq::Callback,是可以绑定MessageHandler,用来Handler2Queue投递AsyncInvoke。还有SYNC2ASYNC宏,所以shortlink跟longlink的OnResponse是AsyncInvoke进行的。还有ASYNC_BLOCK_START宏,StartTask也是AsyncInvoke进行的。整个设计有一个核心关键字,就是RunLoop,所有东西都要绕进来,什么类几乎都有一个RunLoop函数。还有就是Breadker,它为Condition又起了一个名。所以有这么一个函数BreakMessageQueueRunloop,从字面上还以为要中断一个线程的RunLoop,但实质是在做相反的事,breaker->notify(),快唤醒那个线程。这个RunLoop跟CFRunLoop,CFSocket的编程好像一个性子。

还有就是,所有线程跟messagequeue共用一个mutex。

* 两个线程的runloop居然还要竞争一个锁,然后才能处理自己的mq。
* mqA的runloop居然还要跟mqB的postmessage竞争一个锁。
* mqA的postmessage居然还要跟mqB的postmessage竞争一个锁。

 

既然mars是重度使用boost的,不如直接用asio。查看它的boost版本原来是1.60,boost在1.66才将asio重构成我们今天熟悉的executor。我写过一下关于1.66的boost.asio框架设计

逆向,我扯远了。我只关心应用层的接口就好了。

下面就是应用层的主要接口,还有交互流程。

 

现在逆向看看闭源的部分有哪些

先来解读一下目录结构

目录参考了java包目录结构。

mars是一级包名。下面的子包app,cdn,magicbox,mmdns,sdt,smc,stn。

每个子包,有一个同名的头文件,定义类结构。有一个同名的logic头文件,导出子包的接口,包括模块生命周期hooking (onCreate,onDestroy),logic.cc初始模块。子包里的功能单元称为Manager。所有功能的实现体单元在子包的src子目录。

       
目录 mars stn src
namespace mars:: mars::stn          
  StnManager ShortLink LongLink ShortLinkManager LongLinkManager  
文件   stn.h, stn_logic.h, stn_maanger.h ShortLink.cc LongLink.cc ShortLinkManager.cc LongLinkManager.cc  

再整理一下模块的设计思想,logic是包的接口层,manager是承接层,core是服务层。应用层通过logic调用包的服务,经过manager下达core。包内服务通过core调用应用层的服务,经由manager的callback集回调应用层安置的服务。实现过程是否严格贯彻是另一回事。应用层跟包内都有直接使用manager。

我在逆向分析StartTask时,发现了一个问题,mars::stn::Task总计做了10次copy构造,WTF。

在NetCore::StartTask入口准备AsyncInvoke时,一次

在Message构建过程,总计八次,其中有一个any_cast出来的AysncInvovkeFunction赋值函数无意思地进行了七次。typedef boost::function<void()> AsyncInvokeFunction;

 在执行体里面,再一次,就是第十次。

你没有逆向过,也不知道原来这么funny。他们到底有没有跟踪过自己的代码,问号?似乎单靠xlog发现不了问题。没经过逆向分析谁也不清楚any或boost会编译出来什么,也不会在意这些小事的。传参用引用也不是万事大吉的。

 

本期先到这里,下期再见。

与逆向WeChat(四)相似的内容:

逆向WeChat(四)

本篇在博客园地址https://www.cnblogs.com/bbqzsl/p/18209439 mars 先回顾一下,在上两篇《WeUIEngine》,《EventCenter》。我对wechat如何使用chrome::base框架的分析中需要更正补充。首先要指出,逆向分析是一个过程。需要经过不

逆向WeChat(三)

本篇在博客园地址https://www.cnblogs.com/bbqzsl/p/18198572 上篇回顾,对象是WEUIEngine。WeUIEngine使用了chrome::base框架,但只用来实现了单一的功能,只为了DUI的动画计时器。 chrome::base框架没有用作主线程的disp

逆向WeChat (二)

本篇在博客园的地址https://www.cnblogs.com/bbqzsl/p/18187099 回顾一下现时网上的资源。 原生 https://github.com/duilib, Ultimate https://github.com/qdtroy/DuiLib_Ultimate 腾讯 ht

逆向wechat

本篇博客园地址https://www.cnblogs.com/bbqzsl/p/18171552 计划来个wechat的逆向系列,包括主程序WeChat,以及小程序RadiumWMPF。 开篇,对WeChat入口进行分析。 depends显示WeChat.exe并没有依赖CRT,入口地址也找到那个S

【逆向专题】【危!!!刑】(一)使用c#+Win32Api实现进程注入到wechat

引言 自从上篇使用Flaui实现微信自动化之后,这段时间便一直在瞎研究微信这方面,目前破解了Window微信的本地的Sqlite数据库,使用Openssl,以及Win32Api来获取解密密钥,今天作为第一张,先简单写一下,获取微信的一些静态数据,以及将自己写的c语言dll通过Api注入到微信进程里面

上周热点回顾(9.18-9.24)

热点随笔: · 蜘蛛的依旧疯狂与园子的新畅想:尝试放出被屏蔽的百度蜘蛛网段 (博客园团队)· 逃不过转行的命运,与互联网无缘了 (哈er)· JDK21来了!附重要更新说明 (DaFanJoy)· 【逆向专题】【危!!!刑】(一)使用c#+Win32Api实现进程注入到wechat (四处观察)· 

逆向通达信 x 逆向微信 x 逆向Qt

本篇在博客园地址https://www.cnblogs.com/bbqzsl/p/18252961 本篇内容包括: win32窗口嵌入Qt UI。反斗玩转signal-slot。最后 通达信 x 微信 x Qt 做手术。 Qt Alien Widget是一种广义的DirectUI。 在UI技术中,D

逆向基础知识

逆向基础知识 1.逆向分析Hello World程序 源码 #include #include int main(int aggc, TCHAR *argv[]) { MessageBox(NULL, L"Hello World!", L"www.baid

【iOS逆向与安全】iOS远程大师:通过H5后台远程查看和协助iPhone设备

在移动设备测试和远程协助的过程中,能够远程查看和协助iPhone设备是一项非常实用的功能。为了解决这一需求,我开发了一款名为**iOS远程大师**的产品,允许用户通过H5后台界面查看和协助越狱或非越狱的iPhone设备。本文将详细介绍iOS远程大师的开发过程和技术实现。

【Android逆向】frida 破解 jwxdxnx02.apk

apk 路径: https://pan.baidu.com/s/1cUInoi 密码:07p9 这题比较简单,主要是用于练习frida 1. 安装apk到手机 需要输入账号密码 2. 使用jdax 查看apk package hfdcxy.com.myapplication; import andr