android微信逆向工程,iOS逆向 - 微信自动添加好友

相关源码:Github地址

一、前言

本篇主要实现在微信上自动添加好友,从而熟悉 iOS 逆向分析的过程。

二、 工具

2.1 MacBook 软件

制作 Tweak 的工具

端口转发,可以让我们通过usb连接手机进行ssh、lldb调试等。主要使用python-client目录下的文件

dump 目标对象的 class 信息的工具.

lldb

> 调试神器,用过的都说好。默认自带,在/Applications/Xcode.app/Contents/Developer/usr/bin/lldb 中。

2.2 越狱iPhone 软件

以下软件在 Cydia 中即可下载

OpenSSH

实现在越狱手机上远程进行 ssh 服务

iOS 工具大部分都需要在 ssh 环境中使用

Cycript

>脚本语言,用于 hook 正在运行的进程,并实时注入代码。

ondeviceconsole

用于在 Terminal 中查看手机的 log

debugserver

用于连接手机进行 lldb 调试的工具。用 Xcode 在手机上进行 app 调试即可生成,在手机目录的 /Developer/usr/bin/ 中。

使用 debugserver 需要先进行处理。因为缺少task_for_pid权限,所以调试不了其他的 app。

先通过 ssh 拷贝 debugserver

scp root@iOSIP:/Developer/usr/bin/debugserver ~/debugserver

减肥

lipo -thin armv7s ~/debugserver -output ~/debugserver

// 看自己手机是armv7s 还是arm64

ldid - Sent.xml debugserver

在使用 ssh 拷贝至手机,完成。

三、 分析

思路:想要实现自动添加好友,则要拿到获取好友请求的方法,以及添加好友的方法。hook 获取好友请求的方法,在接收到好友请求的时候,执行添加好友的方法。

而这些主要逻辑在“新的朋友”界面。

3.1 定位好友请求的方法

3.1.1 UI 分析

想要拿到好友请求的方法,要先拿到方法实现的 ViewController。而这时候可以通过 UI 分析获得。

先打开新的朋友界面。

使用 usbmuxd 进行端口的转发(若手机不卡,可以跳过这步直接使用ssh进行wifi远程连接)

python tcprelay.py -t 22:2222

再使用ssh连接至手机

ssh roothome.php?mod=space&uid=485241 -p 2222

// ssh root@192.168.31.94

查看微信的进程信息

ps -e |grep WeChat

cycript 注入

cycript -p WeChat

eb2a8beed2bf76ee1a5effe47e4eb124.png

查看当前 UI 布局

UIApp.keyWindow.recursiveDescription().toString()

71ea507b461dac7b231018adf16d443e.png

因为知道当前的视图有tableview,所以找到tableview的对象。从上图可以看到该对象的地址为0x18c4be00。

在使用 nextResponder()根据响应者往上找当前的控制器。

4746caff7d2d3fa6bed23ab3da595c37.png

找到当前的控制器,为SayHelloViewController

3.1.2 Log 分析

使用class-dump dump 出微信的 class 信息。

class-dump -S -s -H demo.app -o ~/Document/headers/

// 保存在 ~/Document/headers/ 目录中

再使用 theos 的 logify 工具,该工具用来注入NSLog来打印方法的入参和出参。(就是在所有的方法里面加 log)

logify.pl  ~/Document/headers/SayHelloViewController.h > ~/Desktop/Tweak.xm

注意:一般该Tweak.xm仍然无法执行,需要进行修改:

去掉.cxx_destruct 方法

将HBLogDebug 改为NSLog

去掉所有的delegate

将所有的参数对象类型改成id

去掉所有的weak

再使用theos配置相关文件具体查看前一篇文章, 然后进行make package install 安装至手机。

重新启动微信进入新的朋友界面。

在ssh中使用ondeviceconsole打印手机的 log。

这时用另一个微信号添加自己好友。出发好友请求的方法。可以看到以下的 log

030e6fee05b193be4e2ace376725ab66.png

说明有好友添加请求的时候,会调用

-[SayHelloViewController OnSayHelloDataChange]

3.1.3 动态分析

既然已经知道了当前控制器会调用OnSayHelloDataChange,那么我们可以想如何查看是哪些方法触发了OnSayHelloDataChange,这时候就要用到 lldb + hopper 神器了。

先用 hopper 打开微信的二进制文件。搜索-[SayHelloViewController OnSayHelloDataChange]方法。

可以看到当前方法在微信中的偏移地址0x14a4824。

a324904107dd121e9105d759452c30a7.png

再使用 usbmuxd 转换端口

python tcprelay.py -t 1234:1234

在 ssh 到手机上,开启 debugserver 。

debugserver *:1234 -a "WeChat"

使用新的 terminal 窗口,打开 lldb,连接1234端口,并查看当前所有进程。

此时会卡住一段时间。

// 打开lldb

/Applications/Xcode.app/Contents/Developer/usr/bin/lldb

// 连接端口调试

(lldb) process connect connect://localhost:1234

// 打印所有进程

(lldb) image list -o -f

找到微信在当前手机上的进程内存基地址为0x000b2000(这个值不是不变的)

6658b58b4d0f8eb27e83e42389138ec9.png

通过以上可以找到 [SayHelloViewController OnSayHelloDataChange]方法在手机上的内存地址。即

内存地址 = 进程内存基地址 + 方法偏移地址

使用 br 打断点查看

br s -a "0x000b2000 + 0x14a4824"

f3147316f9b772a46610e25f098747c0.png

接着输入 c 继续运行,重新使用另一微信账号添加好友,会触发该断点。

dedb4374962fde97fda751875529bbf1.png

使用 bt 查看调用栈信息,即哪些方法调用了当前的方法,找到方法的上游。(异步调用的话没办法查看)

0264e86f2aa00439828a2f31fae23ecf.png

第一个表示当前的方法,可以看到在调用此方法前,该进程总共调用了3个方法。

分别计算出这三个方法在微信中的偏移量。

80e68d41f4125fe38dbc8fa7e4900fe0.png

将这三个地址在 hopper 中查看,找到了对应的方法为

// 调用的顺序为从下到上

[SayHelloViewController OnSayHelloDataChange]

[SayHelloDataLogic onFriendAssistAddMsg:]

[FriendAsistSessionMgr OnAddMsgForSpecialSession:MsgList:]

[CMessageMgr MainThreadNotifyToExt:]

从以上方法名可以猜测

[FriendAsistSessionMgr OnAddMsgForSpecialSession:MsgList:]

是用来接收添加好友消息的函数处理,其中MsgList:后面的参数可能为消息的数组,为了证明我们可以打个断点查看下。

8d090ab79dbc1f268bd7720ca27470e0.png

看出r3确实是个数组,同时也得到了消息的对象为CMessageWrap 证明我们是对的。

解释下为什么要看r3,因为在 armv7 中,一个方法的调用,一般寄存器都是这么存储的。前四个参数放在r0~r3,剩下的存放在堆栈中。查看堆栈的话使用x/10 $sp 查看前10个堆栈里的对象地址。

然而FriendAsistSessionMgr这个类可能需要一些初始化,且放在SayHelloViewController中,而我们想要的是不管在哪个控制器里都可以 hook 住上面的消息数组对象。因此我们往上找,[CMessageMgr MainThreadNotifyToExt:],然而里面并没有我们需要的信息。而根据类名我们推测CMessageMgr是用来管理消息的。有可能是在异步执行了消息数组的获取。

因此,重复以上步骤,使用 logify 对CMessageMgr进行 Log 分析。最终锁定了

CMessageMgr MessageReturn: MessageInfo:Event:

6b6bd54fa1e94e8c14148f6f9f5c2a00.png

3.2 定位 通过好友请求的方法

3.2.1 动态分析

我们知道,通过好友请求的方法,是在新的朋友界面,点击接受的时候触发的。(可以通过 Log 分析,然而这里还有另一个比较快速的方法)

3e65f6d1dbba1aeab3dba6f7217575c1.png

同样,我们可以使用 cycript 进行定位。

先按照 3.1 的方法,打印出所有的UI层级。

找到“接受”按钮的对象,(有个技巧,我们知道当前按钮是在某个cell下面的,所以定位这个)。

8d30e97487865372eae94585445c07bd.png

在把该对象的 hidden = 1,看是否隐藏。

#0x186922f0.hidden = 1

发现按钮不见了,证明我们是对的。

而我们知道 UIButton 是继承 UIControl 的,而 UIControl 的话可以通过allTargets 与 allControlEvents查看所有的对象与事件,再使用actionsForTarget:forControlEvent:从而找到触发的方法。

9ed6ae6019760f50894cd8020379e1ff.png

看出所触发的方法为[ContactsItemView onRightBtnAction]

3.2.2 静态分析

既然拿到了方法名,那我们怎么看他具体的实现呢?

接下来就是大名鼎鼎的hopper 登场了。

用 hopper 打开微信的二进制文件,并进行汇编与伪代码的转换。

由于汇编读起来比较晦涩,所以还是进行伪代码的转换,这样效率比较快。点击该按钮进行转换

9f9102dc3cf91df2b590576c275fe943.png

可以得到伪代码

6441fc02b27b370cd5249dcc4df5cd11.png

上图我们看到了

r10 = self;

r5 = r10 + *0x33befe8;

r4 = objc_loadWeakRetained(r5);

r8 = @selector(onContactsItemViewRightButtonClick:);

r11 = [r4 respondsToSelector:r8];

可以得出,r11 = [r5 onContactsItemViewRightButtonClick:btn],而 r5 我们判断为 self 的代{过}{滤}理,这个我们也可以通过在之前用 class-dump 的头文件里面搜索onContactsItemViewRightButtonClick,会发现在ContactsItemViewDelegate中。

也就是[ContactsItemView onRightBtnAction]内部调用了[self.delegate onContactsItemViewRightButtonClick:].

而 ContactsItemView 的delegate为 SayHelloViewController。

再用 hopper 定位onContactsItemViewRightButtonClick。

5470e745521a6ce99de0165c890f9722.png

fe01f17ace3a27e0922d6607158c5ca5.png

看到这里估计会很蒙不知道从何下手。这时候只要加以推测就可以了。

上图中进行了两个if判断,第一个为

r10 = @selector(class);

r2 = loc_1c099bc(@class(CPushContact), r10);

r1 = @selector(isKindOfClass:);

r5 = loc_1c099bc(r4, r1, r2);

loc_1c099d4(r4);

if ((r5 & 0xff) != 0x0) {

可以得出其实是执行了 if([r4 isKindOfClass:[CPushContact class]]);

而r4是什么呢?可以肯定是 CPushContact 对象,不然下面的代码都不执行了。我们可以根据3.1的动态分析,通过lldb打断点,并查看r3寄存器的对象类型,可以看到该对象为 CPushContact 对象。因此r4就是 CPushContact 对象,根据字面意思可以得到就是联系人对象。

继续看下面的代码,可以看到也进行了一次判断if (((loc_1c099bc(r6, @selector(m_bSuspiciousUser)) & 0xff) != 0x0) && ((loc_1c099bc(r6, @selector(isMMContact)) & 0xff) == 0x0)),看到了MMUIAlertView。推测是弹窗的 view ,推测如果是可疑的用户或者当前申请的好友已经是自己的好友,那就进行弹窗。而另一部分为verifyContactWithOpCode:opcode:,推测该部分为添加好友的方法。

可以通过Log 分析或者通过 lldb 打断点,会看到都会进入该方法。且参数分别为 CPushContact 对象与 3。

接着继续分析verifyContactWithOpCode:opcode:方法。主要的部分如下所示。

c5b1969dc7c36ab7819e21100f443b74.png

通过分析,我们可以得到,确认好友申请,显示构造了CContactVerifyLogic对象。再构造了一个CVerifyContactWrap对象,并设置了相关属性,比如m_nsUsrName m_uiScene m_nsTicket.然后通过添加到数组中,通过CContactVerifyLogic对象的startWithVerifyContactWrap:opCode:parentView:fromChatRoom:方法发送。

代码如下:

CContactVerifyLogic *verifyLogic = [[CContactVerifyLogic alloc] init];

CVerifyContactWrap *wrap = [[CVerifyContactWrap alloc] init];

[wrap setM_nsUsrName:contact.m_nsEncodeUserName];

[wrap setM_uiScene:contact.m_uiFriendScene];

[wrap setM_nsTicket:contact.m_nsTicket];

[wrap setM_nsChatRoomUserName:contact.m_nsChatRoomUserName];

wrap.m_oVerifyContact = contact;

AutoSetRemarkMgr *mgr = [[MMServiceCenter defaultCenter] getService:[AutoSetRemarkMgr class]];

id attr = [mgr GetStrangerAttribute:contact AttributeName:1001];

if([attr boolValue]) {

[wrap setM_uiWCFlag:(wrap.m_uiWCFlag | 1)];

}

[verifyLogic startWithVerifyContactWrap:[NSArray arrayWithObject:wrap] opCode:3 parentView:[UIView new] fromChatRoom:NO];

这样我们就得到了 获取好友请求的方法与添加好友的方法。

而这里还有一个问题,就是添加好友的对象是CPushContact,而获得好友请求的对象的CMessageWrap。这里需要进行转换,而转换的方法也在SayHelloViewController中,可以重复上面的分析方法获得。

四、编写Tweak

通过以上的分析,将代码合并起来

%hook CMessageMgr

- (void)MessageReturn:(unsigned int)arg1 MessageInfo:(NSDictionary *)info Event:(unsigned int)arg3 {

%orig;

if (arg1 == 332) {   // 收到添加好友消息

NSString *keyStr = [info objectForKey:@"5"];

if ([keyStr isEqualToString:@"fmessage"]) {

NSArray *wrapArray = [info objectForKey:@"27"];

[self addAutoVerifyWithArray:wrapArray];

}

}

}

%new

- (void)addAutoVerifyWithArray:(NSArray *)ary {

[ary enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

CPushContact *contact = [%c(SayHelloDataLogic) getContactFrom:obj];

if (![contact isMyContact] && [contact.m_nsDes isEqualToString:autoVerifyKeyword]) {

CContactVerifyLogic *verifyLogic = [[%c(CContactVerifyLogic) alloc] init];

CVerifyContactWrap *wrap = [[%c(CVerifyContactWrap) alloc] init];

[wrap setM_nsUsrName:contact.m_nsEncodeUserName];

[wrap setM_uiScene:contact.m_uiFriendScene];

[wrap setM_nsTicket:contact.m_nsTicket];

[wrap setM_nsChatRoomUserName:contact.m_nsChatRoomUserName];

wrap.m_oVerifyContact = contact;

AutoSetRemarkMgr *mgr = [[%c(MMServiceCenter) defaultCenter] getService:%c(AutoSetRemarkMgr)];

id attr = [mgr GetStrangerAttribute:contact AttributeName:1001];

if([attr boolValue]) {

[wrap setM_uiWCFlag:(wrap.m_uiWCFlag | 1)];

}

[verifyLogic startWithVerifyContactWrap:[NSArray arrayWithObject:wrap] opCode:3 parentView:[UIView new] fromChatRoom:NO];

}

}];

}

五、总结

由于整个逆向流程有点繁琐,有时候也不是只要分析一次就可以成功的,需要反反复复的进行UI分析、LOG分析、lldb分析。因此可能在过程中,有些知识没有漏掉,希望大家可以指出。

六、参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/254385.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

免费查询微信好友还在不在了~

最近一周经常被一些人发一些检测好友的消息,目测这东西好像是有条件收费的,然后就想想python是不是能写个免费版的好友检测。 具体可以看看运行结果: 编写脚本会用到以下几个模块 coloramacoloredlogshumanfriendlylxmlqrcoderequestssixrequ…

如何找回删除的微信好友?

如何找回删除的微信好友? 本篇主要是说朋友圈无互动过,也没有任何标签和其他特殊标记,不知道微信号,手机号的微信好友,误删之后如何通过恢复数据方式恢复好友的办法。百度之后主要有如下几种方法:1.朋友圈有…

在Centos Stream 9上Docker的实操教程(四) - Docker腾讯云远程仓库和本地私有仓库

在Centos Stream 9上Docker的实操教程 - Docker腾讯云远程仓库和本地私有仓库 本地镜像发布到腾讯云注册开通腾讯云初始化个人版服务创建仓库推送拉取镜像 私有仓库结语 本地镜像发布到腾讯云 由于官方的docker hub访问由于网络原因,可能会比较慢,博主推…

html输入框 多出的字隐藏,input 输入框获得/失去焦点时隐藏/显示文字(jquery版)

input 输入框获得和失去焦点时隐藏或者显示文字我们先看下效果图 输入框默认状态: 输入框获取焦点状态: 大家可以看效果图的搜索输入框,默认显示着“用户名/Email”的提示,当这个 input 输入框获得焦点时,就自动清空等待用户输入&#xff0c…

【C++】函数高级 - 默认参数,占位参数,函数重载基本语法,函数重载注意事项

No.Contents1【C】基础知识 - HelloWorld,注释,变量,常量,关键字,标识符2【C】数据类型 - 整型,sizeof,实型,字符型,转义字符,字符串类型,布尔类型…

LeetCode 560 和为 K 的子数组

LeetCode 560 和为 K 的子数组 来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/subarray-sum-equals-k/description 博主Github:https://github.com/GDUT-Rp/LeetCode 题目: 给你一个整数数组 …

chatgpt赋能python:Python中的画图——创建漂亮的可视化图像

Python中的画图——创建漂亮的可视化图像 Python是一个高度可编程的语言,因此它非常适合用于创建各种类型的可视化。 在本文中,我们将介绍Python中的画图。我们将讨论如何使用Python和一些流行的数据可视化库来创建漂亮的可视化图像。我们还将探讨如何…

【Linux】Linux文件权限的理解

目录 一、Shell是什么? 1、Shell承担用户和内核间的翻译工作 2、拒绝用户非法请求,保护内核 3、派生子进程执行用户指令 二、用户切换与提权 1、普通用户与root用户的切换 2、普通用户指令短暂提权 三、文件权限的理解 1、文件权限角色的权限文…

Linux文件的rwx含义,Linux文件权限rwx简单了解

Ⅰ 了解Linux下的文件权限 如上图所示,ll命令详细展示当前目录下的文件或者子目录信息 红框标注的即为此文件或者目录的权限 【第一行文件10.c的权限以-开头,用来说明这是一个文件;第四行code目录的权限以字母d开头,用来标注code是目录】 关于文件权限,我们要先了解有那些…

Linux文件权限管理命令

今天继续给大家介绍Linux基本知识,本文主要内容是介绍Linux文件权限相关命令。 一、chown命令修改文件属主 在Linux系统中,chown命令可以更改文件的属主和属组,chown命令使用示例如下: chown user.user target chown user:user…

Linux文件权限修改

Linux文件权限修改 一.文件属性查看 使用root创建一个1.txt文件进行实例 touch /opt/1.txt查看文件属性 ls -l /opt/1.txt可以看到图中红色框框内列出了文件的信息属性,从左到有进行性详解 1. -rw-r--r-- 参考下图进行理解 共有10个字符,如果第一个…

Linux文件权限的设置

本文章主要介绍了对Linux文件的权限以及如何设置权限。 一、查看文件的权限与属性 ls -l 或者 ll查看文件属性 二、可以列出如下图所示的一些信息 -rw-r--r-- 第一位代表文件类型 d 表示目录 l 表示链接文件 - 表示普通文件 b 表示快设备文…

Linux文件权限查看与修改

Linux文件的权限 linux文件的权限可以分为四类:可读、可写、可执行、没有权限。分别用字符r、w、x、- 表示。 2. 用户与用户组 Linux是一个多用户多任务的操作系统,可以通过用户和用户组来更好的控制文件的权限。 每个文件都有一个拥有者(某一…

【C++入门】什么是内联函数?

目录 一、概念 为什么要有内联函数? 内联函数设计的初衷是为了替代部分 #define 宏定义 二、特性 1.空间换时间 2.编译器做主 3.声明定义放一起 总结 一、概念 以inline修饰的函数叫做内联函数,编译时C编译器会在调用函数的地方展开,没有…

CAD圆弧

import dxfgrabberinputFilePathe:/test3-11/Drawing2.dxf #输入文件的路径dxf dxfgrabber.readfile(inputFilePath)#按图层访问 # for layer in dxf.layers: # #print(layer.name,layer.color,layer.linetype) # print("图层名:",layer.name)l…

CAD电气制图中怎么用圆弧连接导线?

在CAD电气制图过程中经常会需要连接两条导线,那么你知道CAD软件中怎么用圆弧连接两条导线呢?浩辰CAD电气软件中提供了便捷的圆弧连接功能,接下来的CAD电气制图教程就和小编一起来看看浩辰CAD电气软件中圆弧连接功能的相关使用技巧吧&#xff…

php中划弧线,cad画弧形的快捷键是什么?如何画弧形?

cad画弧形的快捷键是A,画弧形的方法:首先确定圆心,并点击圆弧命令;接着继续输入C进行圆心的确定,并调整半径和位置;最后点击选择两个端点后exc退出即可完成。 cad画弧形的快捷键是A,画弧形的方法…

你知道CAD软件将圆弧与直线转换成多段线的方法吗?

CAD制图时想要对直线与圆弧构成的整体对象进行多段线编辑,首先需要将这个对象转换成多段线。本文将介绍CAD如何将直线与圆弧连接成多段线。 1.使用CAD软件打开需要进行操作的图纸文件,用夹点拾取一下,从右边的特性栏可以看到这个图形是由4条…

圆弧的绘制

圆弧的分类 圆心/起/终点画圆弧 其操作方法类似于圆命令,第一次单击鼠标左键,确定圆心,移动鼠标,再次单击鼠标左键确定半径,最后通过移动鼠标来确定圆弧长度(若不移动就单击鼠标左键,则取消该次…

AUTOCAD——圆弧命令

创建圆弧。 执行方式 命令行:AEC 菜单栏:绘图→圆弧 工具栏:圆弧命令图标 “圆弧命令操作命令位置”界面 执行以上命令后,命令行会显示以下信息: 选项说明 (1)起点:指定第一个点…