iOS逆向工程整理_HOOK微信抢红包_0x02

原理

原理上篇已经说过了,利用iOS的runtime特效,替换方法的实现来达到HOOK的目的。本篇是一个实战教程,讲解怎么来Hook微信的自动抢红包。

第1步:砸壳

首先ssh连上越狱iOS设备,执行ps -e查找微信的app地址
这里写图片描述
这里的app路径是/var/mobile/Containers/Bundle/Application/690828B8-B63F-4FAC-B7CC-DEFD8E23AF46/WeChat.app/WeChat,记下来先。
然后进入Cycript,查找出微信的Documents目录
这里写图片描述
把这个路径记下来/var/mobile/Containers/Data/Application/2B65DCC1-9FAD-41C8-A5EC-C3D9326EE3D6/Documents/
然后退出cycript,cd到documents目录下,执行以下命令:

adminde-iPhone:~ root# 
adminde-iPhone:/var/mobile/Containers/Data/Application/2B65DCC1-9FAD-41C8-A5EC-C3D9326EE3D6/Documents root# DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/Application/690828B8-B63F-4FAC-B7CC-DEFD8E23AF46/WeChat.app/WeChat

mach-o decryption dumper

DISCLAIMER: This tool is only meant for security research purposes, not for application crackers.

[+] detected 32bit ARM binary in memory.
[+] offset to cryptid found: @0xd7a4c(from 0xd7000) = a4c
[+] Found encrypted data at address 00004000 of length 49463296 bytes - type 1.
[+] Opening /private/var/mobile/Containers/Bundle/Application/690828B8-B63F-4FAC-B7CC-DEFD8E23AF46/WeChat.app/WeChat for reading.
[+] Reading header
[+] Detecting header type
[+] Executable is a FAT image - searching for right architecture
[+] Correct arch is at offset 16384 in the file
[+] Opening WeChat.decrypted for writing.
[+] Copying the not encrypted start of the file
[+] Dumping the decrypted data into the file
[+] Copying the not encrypted remainder of the file
[+] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset 4a4c
[+] Closing original file
[+] Closing dump file
adminde-iPhone:/var/mobile/Containers/Data/Application/2B65DCC1-9FAD-41C8-A5EC-C3D9326EE3D6/Documents root# ls 
WeChat.decrypted

WeChat.decrypted文件就是我们砸壳后的二进制文件,我们可以拷贝到Mac上,各种工具都可以用上了。

第2步:导出头文件

使用class-dump,将我们砸壳出来的二进制文件的头文件导出来:

admindeMac-mini:微信6.5.5 admin$ class-dump --arch armv7  -s -S -H WeChat.decrypted -o headers/
admindeMac-mini:微信6.5.5 admin$ ls headers/
AAAlertItem.h
AACloseNotifyReq.h
AACloseNotifyRes.h
AACloseReq.h
AACloseRes.h
AALaunchByMoneyReq.h
AALaunchByMoneyRes.h
AALaunchByPersonReq.h
AALaunchByPersonRes.h
AALaunchItem.h
AAListRecord.h
AAOperationReq.h
AAOperationRes.h
AAPayReq.h
AAPayRes.h

可以看到微信的头文件有8500多个(汗),如此茫茫代码海出如何找出我们需要的那一部分呢?

第2步:精准定位我们想要HOOK的代码

iOS开发是遵循MVC模式的,所以我们需要找到这个M模型层来找到我需要的业务逻辑代码。抢红包的原理是通过截取微信收到了红包消息,然后直接调用打开红包的接口来实现自动抢红包。
通过查找发现CMessageMgr这个类就是用来管理各种消息的,查看CMessageMgr.h头文件

- (void)AddAppMsg:(id)arg1 MsgWrap:(id)arg2 Data:(id)arg3 Scene:(unsigned long)arg4;
- (void)AddAppMsg:(id)arg1 MsgWrap:(id)arg2 DataPath:(id)arg3 Scene:(unsigned long)arg4;
- (BOOL)AddBackupMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AddEmoticonMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AddFloatBottle:(id)arg1 MsgWrap:(id)arg2;
- (void)AddHelloMsg:(id)arg1 MsgWrap:(id)arg2 HelloUser:(id)arg3 OpCode:(unsigned long)arg4 DES:(unsigned long)arg5 checkCreateTime:(BOOL)arg6 status:(unsigned long)arg7;
- (void)AddHelloMsgList:(id)arg1 MsgList:(id)arg2;
- (void)AddLocalMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AddLocalMsg:(id)arg1 MsgWrap:(id)arg2 fixTime:(BOOL)arg3 NewMsgArriveNotify:(BOOL)arg4;
- (void)AddLocalMsg:(id)arg1 MsgWrap:(id)arg2 fixTime:(BOOL)arg3 NewMsgArriveNotify:(BOOL)arg4 Unique:(BOOL)arg5;
- (void)AddMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AddMsgPattern:(id)arg1;
- (void)AddPimMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AddRecordMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AddShortVideoLocalMsg:(id)arg1 ToUsr:(id)arg2 VideoInfo:(id)arg3 MsgType:(unsigned long)arg4;
- (void)AddShortVideoMsg:(id)arg1 ToUsr:(id)arg2 VideoInfo:(id)arg3;
- (void)AddUniqueLocalMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AddVideoMsg:(id)arg1 ToUsr:(id)arg2 VideoInfo:(id)arg3;
- (void)AddVideoMsg:(id)arg1 ToUsr:(id)arg2 VideoInfo:(id)arg3 MsgType:(unsigned long)arg4;
- (void)AsyncOnAddMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AsyncOnAddMsgForSession:(id)arg1 MsgWrap:(id)arg2;
- (void)AsyncOnAddMsgForSession:(id)arg1 MsgWrap:(id)arg2 NewMsgArriveNotify:(BOOL)arg3;
- (void)AsyncOnAddMsgListForSession:(id)arg1 NotifyUsrName:(id)arg2;
- (void)AsyncOnCheckQQ;
- (void)AsyncOnDelMsg:(id)arg1;
- (void)AsyncOnDelMsg:(id)arg1 DelAll:(BOOL)arg2;
- (void)AsyncOnDelMsg:(id)arg1 MsgWrap:(id)arg2;
- (void)AsyncOnModMsg:(id)arg1 MsgWrap:(id)arg2;

通过猜想假设,再加上编写Tweak脚本测试,发现我们想要的接受消息的函数是AsyncOnAddMsg这个函数。找到接受消息的函数后接下来,我们要找打开红包的函数。
在头文件目录下搜索OpenRedEnvelope

grep -nR 'OpenRedEnvelope' ./
.//WCAtomicRedEnvReceiveHomeView.h:15:    UIButton *m_oOpenRedEnvelopesButton;
.//WCAtomicRedEnvReceiveHomeView.h:31:- (void)OnOpenRedEnvelopes;
.//WCAtomicRedEnvReceiveHomeViewDelegate-Protocol.h:12:- (void)WCAtomicRedEnvReceiveHomeViewOpenRedEnvelopes:(_Bool)arg1;
.//WCFestivalRedEnvFinishView.h:28:- (void)OnOpenRedEnvelopes;
.//WCFestivalRedEnvReceiveHomeView.h:31:- (void)OnOpenRedEnvelopes;
.//WCFestivalRedEnvReceiveHomeViewDelegate-Protocol.h:12:- (void)WCFestivalRedEnvReceiveHomeViewOpenRedEnvelopes:(_Bool)arg1;
.//WCFestivalRedEnvShareView.h:28:- (void)OnOpenRedEnvelopes;
.//WCRedEnvelopesControlData.h:31:    NSDictionary *m_structDicAfterOpenRedEnvelopesInfo;
.//WCRedEnvelopesControlData.h:49:@property(retain, nonatomic) NSDictionary *m_structDicAfterOpenRedEnvelopesInfo; // @synthesize m_structDicAfterOpenRedEnvelopesInfo;
.//WCRedEnvelopesEnterpriseControlLogic.h:39:- (void)WCFestivalRedEnvReceiveHomeViewOpenRedEnvelopes:(_Bool)arg1;
.//WCRedEnvelopesGreetingReceiveControlLogic.h:37:- (void)OnOpenRedEnvelopesRequest:(id)arg1 Error:(id)arg2;
.//WCRedEnvelopesGreetingReceiveControlLogic.h:52:- (void)WCRedEnvelopesReceiveHomeViewOpenRedEnvelopes;
.//WCRedEnvelopesLogicMgr.h:42:- (void)OpenRedEnvelopesRequest:(id)arg1;

我们猜想WCRedEnvelopesLogicMgr.h里面的OpenRedEnvelopesRequest函数就是我们要找的目标函数,经常反复的测试和验证,这个函数确实是我们要的打开红包的函数。

第3步:写代码完成开发

经历了以上分析和验证的过程,写代码对于HOOK来说反而是很简单的水到渠成。具体抢红包的代码如下:

@class CMessageMgr;

CHDeclareClass(CMessageMgr);

CHOptimizedMethod(2, self, void, CMessageMgr, AsyncOnAddMsg, id, arg1, MsgWrap, id, arg2) {
    CHSuper(2, CMessageMgr, AsyncOnAddMsg, arg1, MsgWrap, arg2);
    Ivar uiMessageTypeIvar = class_getInstanceVariable(objc_getClass("CMessageWrap"), "m_uiMessageType");
    ptrdiff_t offset = ivar_getOffset(uiMessageTypeIvar);
    unsigned char *stuffBytes = (unsigned char *)(__bridge void *)arg2;
    NSUInteger m_uiMessageType = * ((NSUInteger *)(stuffBytes + offset));

    Ivar nsFromUsrIvar = class_getInstanceVariable(objc_getClass("CMessageWrap"), "m_nsFromUsr");
    id m_nsFromUsr = object_getIvar(arg2, nsFromUsrIvar);

    Ivar nsContentIvar = class_getInstanceVariable(objc_getClass("CMessageWrap"), "m_nsContent");
    id m_nsContent = object_getIvar(arg2, nsContentIvar);

    switch(m_uiMessageType) {
        case 1: {
        }
            break;

        case 49: {
            // 49=红包
            //微信的服务中心
            Method methodMMServiceCenter = class_getClassMethod(objc_getClass("MMServiceCenter"), @selector(defaultCenter));
            IMP impMMSC = method_getImplementation(methodMMServiceCenter);
            id MMServiceCenter = impMMSC(objc_getClass("MMServiceCenter"), @selector(defaultCenter));
            //红包控制器
            id logicMgr = ((id (*)(id, SEL, Class))objc_msgSend)(MMServiceCenter, @selector(getService:), objc_getClass("WCRedEnvelopesLogicMgr"));
            //通讯录管理器
            id contactManager = ((id (*)(id, SEL, Class))objc_msgSend)(MMServiceCenter, @selector(getService:),objc_getClass("CContactMgr"));

            Method methodGetSelfContact = class_getInstanceMethod(objc_getClass("CContactMgr"), @selector(getSelfContact));
            IMP impGS = method_getImplementation(methodGetSelfContact);
            id selfContact = impGS(contactManager, @selector(getSelfContact));

            if ([m_nsContent rangeOfString:@"wxpay://"].location != NSNotFound)
            {
                NSString *nativeUrl = m_nsContent;
                NSRange rangeStart = [m_nsContent rangeOfString:@"wxpay://c2cbizmessagehandler/hongbao"];
                if (rangeStart.location != NSNotFound)
                {
                    NSUInteger locationStart = rangeStart.location;
                    nativeUrl = [nativeUrl substringFromIndex:locationStart];
                }

                NSRange rangeEnd = [nativeUrl rangeOfString:@"]]"];
                if (rangeEnd.location != NSNotFound)
                {
                    NSUInteger locationEnd = rangeEnd.location;
                    nativeUrl = [nativeUrl substringToIndex:locationEnd];
                }

                NSString *naUrl = [nativeUrl substringFromIndex:[@"wxpay://c2cbizmessagehandler/hongbao/receivehongbao?" length]];

                NSArray *parameterPairs =[naUrl componentsSeparatedByString:@"&"];

                NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithCapacity:[parameterPairs count]];
                for (NSString *currentPair in parameterPairs) {
                    NSRange range = [currentPair rangeOfString:@"="];
                    if(range.location == NSNotFound)
                        continue;
                    NSString *key = [currentPair substringToIndex:range.location];
                    NSString *value =[currentPair substringFromIndex:range.location + 1];
                    [parameters setObject:value forKey:key];
                }

                //红包参数
                NSMutableDictionary *params = [@{} mutableCopy];

                [params setObject:parameters[@"msgtypes"]?:@"null" forKey:@"msgType"];
                [params setObject:parameters[@"sendid"]?:@"null" forKey:@"sendId"];
                [params setObject:parameters[@"channelid"]?:@"null" forKey:@"channelId"];

                id getContactDisplayName = objc_msgSend(selfContact, @selector(getContactDisplayName));
                id m_nsHeadImgUrl = objc_msgSend(selfContact, @selector(m_nsHeadImgUrl));

                [params setObject:getContactDisplayName forKey:@"nickName"];
                [params setObject:m_nsHeadImgUrl forKey:@"headImg"];
                [params setObject:[NSString stringWithFormat:@"%@", nativeUrl]?:@"null" forKey:@"nativeUrl"];
                [params setObject:m_nsFromUsr?:@"null" forKey:@"sessionUserName"];

                ((void (*)(id, SEL, NSMutableDictionary*))objc_msgSend)(logicMgr, @selector(OpenRedEnvelopesRequest:), params);

                return;
            }

            break;
        }
        default:
            break;
    }
}

以上就是微信抢红包的分析和代码过程,才有的是越狱方式开发,打包的dylib动态链接库文件是直接放入到系统文件目录里面的。至于非越狱开发,要更复杂一点,涉及到原始app文件的解包,修改,添加动态链接库,然后再签名打包的一系列复杂过程。仅供参考和学习用,请勿用于商业用途,否则后果自负!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值