马上就要过年了相信大家已经在钉钉里抢过一波红包了,也有些同学可能没有抢到比如说我。那除夕夜的红包大家应该不能再错过了吧,钉钉的自动抢红包之前也有很多大神写过了,比如说这里虽然版本有些旧了,我就在这个基础上又研究了一下。至于准备工具之类的我就不多说了,看我之前的文章里面有的。下面开始。
步骤
- 找到打开红包的方法
- 获取到最新红包的消息,调用打开红包的方法
分析
我们可以看到红包的类
DTRedEnvelopPickView
我们现在就到这个类里去寻找打开红包的方法。我们可以找到unpack
的方法,但是这个是执行的一个block
我们直接hook到
unpack
方法利用xcode调试看看到底里面执行了什么方法。
CHOptimizedMethod(0, self,void,DTRedEnvelopPickView,unpack){
CHSuper(0, DTRedEnvelopPickView,unpack);
}
点击打开红包后断点到这里,我们执行下一步就会看到
我们进入这个
DTRedEnvelopServiceIMP
头文件可以搜索到- (void)pickRedEnvelopCluster:(long long)arg1 clusterId:(id)arg2 successBlock:(CDUnknownBlockType)arg3
这个方法。现在我们就清楚了这个就是打开红包的方法。然后我们继续分析最新消息的方法,我们通过xcode调试可以知道消息页面是DTBizConversation
我们进入这个类可以看到setLastMessage
方法,可以猜到这个应该是设置最新一条消息的,我们可以hook这个方法加一个断点,然后找同事给我们发一个消息,断点到了后我们就能看到我们根据方法名就能猜出
- (void)controller:(id)arg1 didChangeObject:(id)arg2 atIndex:(unsigned long long)arg3 forChangeType:(long long)arg4 newIndex:(unsigned long long)arg5;
这个方法就是监听新消息的方法。我们hook到这个方法同样打断点。然后让同事发个红包给我们,就能找到第二个参数是一个聊天对象我们打印
_latestMessage
可以看到一个消息的数据,然后我们打开红包断点到- (void)pickRedEnvelopCluster:(long long)arg1 clusterId:(id)arg2 successBlock:(CDUnknownBlockType)arg3
这个打开红包方法里,看下传过去的参数,分析后就能找到是senderId和clusterId
这两个我们在消息数据里可以拿到。现在就明确了,我们hook消息改变的方法判断是红包类型(红包类型为901和902)然后发送打开红包消息。
CHDeclareClass(DTConversationListDataSource)
CHOptimizedMethod(5, self,void,DTConversationListDataSource,controller,id,arg1,didChangeObject,id,arg2,atIndex,unsigned long long,arg3,forChangeType,long long,arg4,newIndex,unsigned long long,arg5){
CHSuper(5, DTConversationListDataSource,controller,arg1,didChangeObject,arg2,atIndex,arg3,forChangeType,arg4,newIndex,arg5);
NSLog(@"%@",arg2);
NSString *json = CHIvar(arg2, _latestMessageJson, __strong NSString *);
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
NSInteger type = [[data valueForKey:@"attachmentsType"] intValue];
if(type == 902 || type == 901){
if(![data[@"isRead"] boolValue]){
NSString *clusterId = data[@"safeExtension"][@"clusterId"];
long long sendId = [data[@"senderId"] longLongValue];
// id (*typed_msgSend)(id, SEL) = (void *)objc_msgSend;
id imp = [NSClassFromString(@"DTRedEnvelopServiceIMP") new];
// id protocl = CHIvar(imp, _networkIMP, __weak id);
if (clusterId.length > 0){
// pickRedEnvelopCluster:(long long)arg1 clusterId:(id)arg2 successBlock:(CDUnknownBlockType)arg3 failureBlock:(CDUnknownBlockType)arg4
//拆红包
id (*openRed_msgSend)(id, SEL,long long,id,id,id) = (void *)objc_msgSend;
openRed_msgSend(imp,NSSelectorFromString(@"pickRedEnvelopCluster:clusterId:successBlock:failureBlock:"),sendId,clusterId,nil,nil);
}
}
}
}
我们打好断点让同事发个红包,我们可以看到方法都执行了但是好像红包没有被领取,我们可以猜测我们创建的DTRedEnvelopServiceIMP
对象是不是有问题,我们hook这个类的init
方法打上断点看看它是怎么被创建的,重新运行,断点到了后我们可以看到
是这个类调用了
DTRedEnvelopServiceFactory
我们直接进这个类的头文件发现如下代码
#import <Foundation/NSObject.h>
@interface DTRedEnvelopServiceFactory : NSObject
{
}
+ (id)createServiceIMPWithPersistence:(id)arg1 network:(id)arg2;
+ (id)defaultServiceIMP;
@end
看到defaultServiceIMP
我们应该就知道了我们调用这个方法创建出来就可以了
编码
方法我们都找到了要传什么参数也知道了这样就可以编写了,最终代码如下
//消息改变 拿到最新消息
CHOptimizedMethod(5, self,void,DTConversationListDataSource,controller,id,arg1,didChangeObject,id,arg2,atIndex,unsigned long long,arg3,forChangeType,long long,arg4,newIndex,unsigned long long,arg5){
CHSuper(5, DTConversationListDataSource,controller,arg1,didChangeObject,arg2,atIndex,arg3,forChangeType,arg4,newIndex,arg5);
NSLog(@"%@",arg2);
NSString *json = CHIvar(arg2, _latestMessageJson, __strong NSString *);
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
NSInteger type = [[data valueForKey:@"attachmentsType"] intValue];
if(type == 902 || type == 901){
if(![data[@"isRead"] boolValue]){
NSString *clusterId = data[@"safeExtension"][@"clusterId"];
long long sendId = [data[@"senderId"] longLongValue];
id (*typed_msgSend)(id, SEL) = (void *)objc_msgSend;
id imp = typed_msgSend(objc_getClass("DTRedEnvelopServiceFactory"),NSSelectorFromString(@"defaultServiceIMP"));
// id protocl = CHIvar(imp, _networkIMP, __weak id);
if (clusterId.length > 0){
// pickRedEnvelopCluster:(long long)arg1 clusterId:(id)arg2 successBlock:(CDUnknownBlockType)arg3 failureBlock:(CDUnknownBlockType)arg4
//拆红包
id (*openRed_msgSend)(id, SEL,long long,id,id,id) = (void *)objc_msgSend;
openRed_msgSend(imp,NSSelectorFromString(@"pickRedEnvelopCluster:clusterId:successBlock:failureBlock:"),sendId,clusterId,nil,nil);
}
}
}
}
逆向就是一步一步分析的过程,也要有比较敏锐的“嗅觉”,看到一个方法就能猜测到是做什么的。这个时候你编译运行到自己设备上让别人给你发个红包应该就会秒抢到了。有个问题就是这样用自己证书打包的话推送就收不到了。不过不影响我们抢红包。
代码在这里