新的博客地址
@[toc]
前言
I 、hookMethod、ClassMethod
#import
#import
@interface KNHook : NSObject
/**
替换对象方法
@param originalClass 原始类
@param originalSelector 原始类的方法
@param swizzledClass 替换类
@param swizzledSelector 替换类的方法
*/
void kn_hookMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector);
/**
替换类方法
@param originalClass 原始类
@param originalSelector 原始类的类方法
@param swizzledClass 替换类
@param swizzledSelector 替换类的类方法
*/
void kn_hookClassMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector);
1.1 替换对象方法
/**
替换对象方法
@param originalClass 原始类
@param originalSelector 原始类的方法
@param swizzledClass 替换类
@param swizzledSelector 替换类的方法
*/
void kn_hookMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector){
Method originalMethod = class_getInstanceMethod(originalClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(swizzledClass, swizzledSelector);
if(originalMethod && swizzledMethod) {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
1.2 替换类方法
/**
替换类方法
@param originalClass 原始类
@param originalSelector 原始类的类方法
@param swizzledClass 替换类
@param swizzledSelector 替换类的类方法
*/
void kn_hookClassMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector){
Method originalMethod = class_getClassMethod(originalClass, originalSelector);
Method swizzledMethod = class_getClassMethod(swizzledClass, swizzledSelector);
if(originalMethod && swizzledMethod) {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
1.3 使用例子
- hook OnSyncBatchAddMsgs
static void __attribute__((constructor)) initialize(void) {
MSHookMessageEx(objc_getClass("MessageService"), @selector(OnSyncBatchAddMsgs:isFirstSync:), (IMP)&new_MessageService_OnSyncBatchAddMsgs_isFirstSync, (IMP*)&origin_new_MessageService_OnSyncBatchAddMsgs_isFirstSync);
[NSObject hookWeChat];
}
- hook CUtility
#import "NSObject+WeChatHook.h"
@implementation NSObject (WeChatHook)
+ (void)hookWeChat {
kn_hookClassMethod(objc_getClass("CUtility"), @selector(HasWechatInstance), [self class], @selector(hook_HasWechatInstance));
}
#pragma mark - hook 方法
/**
hook 是否已启动
*/
+ (BOOL)hook_HasWechatInstance {
NSLog(@"kn hook_HasWechatInstance");
return NO;
}
@end
II 、使用substrate.h
进行hook
static void (*origin_new_MessageService_OnSyncBatchAddMsgs_isFirstSync)(MessageService*,SEL,NSArray *,BOOL);
static void new_MessageService_OnSyncBatchAddMsgs_isFirstSync(MessageService* self,SEL _cmd,NSArray * msgs,BOOL isFirstSync){
origin_new_MessageService_OnSyncBatchAddMsgs_isFirstSync(self,_cmd,msgs,isFirstSync);
}
III 、Wechat笔记
3.1 CMessageWrap是对消息数据的封装。
CMessageWrap *myMsg = [[NSClassFromString(@"CMessageWrap") alloc] initWithMsgType:3 nsFromUsr:toUser];
- 设置发送的对象微信ID
reWrap.m_nsToUsr = other_wxId;
3.2 自己给自己发送消息
- (void)checkHeartMsg
{
NSLog(@"checkHeartMsg 发送消息给自己");
// CMessageWrap *myMsg = [[NSClassFromString(@"CMessageWrap") alloc] initWithMsgType:3 nsFromUsr:""];//nsFromUsr 自己的微信号
// reWrap.m_nsToUsr = "";// 自己的微信号
// [self sendMsg:@"hi" toContactUsrName:@"ruiriimama"];
// id userName = @"ruiriimama";
// int y = (arc4random() % 501) + 500;
id msg = [NSString stringWithFormat:@"hi%.4d", arc4random()%100];
CMessageWrap *wrap = [[%c(CMessageWrap) alloc] initWithMsgType:1];
id usrName = [%c(SettingUtil) getLocalUsrName:0];
id userName = usrName;
NSLog(@"usrName%@",usrName);
[wrap setM_nsFromUsr:usrName];
[wrap setM_nsContent:msg];
[wrap setM_nsToUsr:userName];
// MMNewSessionMgr *sessionMgr = [[%c(MMServiceCenter) defaultCenter] getService:%c(MMNewSessionMgr)];
// [wrap setM_uiCreateTime:[sessionMgr GenSendMsgTime]];
[wrap setM_uiStatus:YES];
CMessageMgr *chatMgr = [[%c(MMServiceCenter) defaultCenter] getService:%c(CMessageMgr)];
[chatMgr AddMsg:userName MsgWrap:wrap];
}
3.3获取当前时间的方法
reWrap.m_uiCreateTime = [objc_getClass("CUtility") genCurrentTime];
MMNewSessionMgr *sessionMgr = [[%c(MMServiceCenter) defaultCenter] getService:%c(MMNewSessionMgr)];
[wrap setM_uiCreateTime:[sessionMgr GenSendMsgTime]];
3.4获取自己微信号的方法
reWrap.m_nsFromUsr = [objc_getClass("SettingUtil") getLocalUsrName:0];
获取自己微信昵称的方式
id usrName = [%c(SettingUtil) getLocalUsrName:0];
3.5 发送微信名片
- 发送名片
//发送名片
%new
-(void)sendCardMessage:(NSString *)toUser toContact:(CContact *)toContact{
NSLog(@"开始发名片 toUser:%@ toContact:%@",toUser,toContact);
id mgrCard = [[NSClassFromString(@"MMServiceCenter") defaultCenter] getService:NSClassFromString(@"CMessageMgr")];
id msgCard = [[NSClassFromString(@"CMessageWrap") alloc] initWithMsgType:0x2a];
[msgCard setM_nsToUsr:toUser];
[msgCard setM_nsFromUsr:[m_nCSetting m_nsUsrName]];
[msgCard setM_nsContent:[toContact xmlForMessageWrapContent]];
MMNewSessionMgr *sessionMgr = [[%c(MMServiceCenter) defaultCenter] getService:%c(MMNewSessionMgr)];
[msgCard setM_uiCreateTime:[sessionMgr GenSendMsgTime]];
// [msgCard setM_uiCreateTime:(int)time(NULL)];
[mgrCard AddMsg:toUser MsgWrap:msgCard];
}
- 加载通讯录
else if ([[wrap m_nsContent] hasPrefix:@"$xlllll,"]){
//得到通讯录的信息
FTSContactMgr *ftsContactMgr = [[[NSClassFromString(@"MMServiceCenter") defaultCenter] getService:NSClassFromString(@"FTSFacade")] ftsContactMgr];
NSMutableDictionary *dicContact = [ftsContactMgr getContactDictionary];
NSArray *arr = [[wrap m_nsContent] componentsSeparatedByString:@","];
if (arr.count<=2) {
return;
}
NSString *wxid = arr[2];//名片的微信号
NSLog(@"sendCardMessage wxid %@",wxid);
NSString *toUser = arr[1];//发送给特定的用户
NSLog(@"sendCardMessage toUser %@",toUser);
CContact *oneContact = [dicContact objectForKey:wxid];
[self sendCardMessage:toUser toContact:oneContact];
}
3.6 好友管理相关的功能
- 判断入群方式
- (void)AsyncOnPreAddMsg:(id)arg1 MsgWrap:(CMessageWrap *)arg2 {
%orig;
NSLog((@"\n\n函数名\n%s "),__FUNCTION__);
NSLog(@"\n发信人 %@ \n 收信人 %@ \n 正文 %@\n 类型 %lld\n ID %@ \n %@ \n end",
arg2.m_nsFromUsr,arg2.m_nsRealChatUsr,arg2.m_nsContent,(long long)arg2.m_uiMessageType,arg2.m_nsRealChatUsr,arg2.m_nsToUsr);
/*
CContactMgr *contactManager = [[objc_getClass("MMServiceCenter") defaultCenter] getService:[objc_getClass("CContactMgr") class]];
CContact *selfContact = [contactManager getSelfContact];
NSLog(@"\n\n\nself = %@ ---- %@",selfContact.m_nsUsrName,arg2.m_nsToUsr);
*/
if (![arg1 hasSuffix:@"@chatroom"]) {
NSLog(@"不是群聊,不是群聊,不是群聊");
return;
}
NSArray *result = (NSArray *)[objc_getClass("CContact") getChatRoomMemberWithoutMyself:arg2.m_nsFromUsr];
for (CContact * contact in result) {
if ([contact.m_nsUsrName isEqualToString: arg2.m_nsRealChatUsr]) {
SaulWeChatPublicClass * saul = [SaulWeChatPublicClass sharedInstance];
[saul getAtCContactWith:contact];
NSLog(@"\n\n\n 找到了 %@ \n %@",contact,saul.atContact);
}
}
switch(arg2.m_uiMessageType) {
case 10002: { // 扫码入群
SaulWeChatPublicClass * saul = [SaulWeChatPublicClass sharedInstance];
if ([arg2.m_nsFromUsr hasSuffix:@"@chatroom"]) {
if ([saul.addGroupDict objectForKey:arg2.m_nsFromUsr]) {
int num = [[saul.addGroupDict objectForKey:arg2.m_nsFromUsr] integerValue];
NSString * value = [NSString stringWithFormat:@"%lld",(long long)num+1];
[saul.addGroupDict setValue:value forKey:arg2.m_nsFromUsr];
} else {
[saul.addGroupDict setValue:@"1" forKey:arg2.m_nsFromUsr];
}
}
saul.addGroupNum = [[saul.addGroupDict objectForKey:arg2.m_nsFromUsr] integerValue];
if (saul.addGroupNum >= saul.senMessageCount) {
[saul sendMessage:arg2];
saul.addGroupNum = 0;
[saul.addGroupDict setValue:@"1" forKey:arg2.m_nsFromUsr];
}
break;
}
/*
case 10000: { // 邀请入群
SaulWeChatPublicClass * saul = [SaulWeChatPublicClass sharedInstance];
saul.addGroupNum += 1;
if (saul.addGroupNum == 2) {
[saul sendMessage:arg2];
saul.addGroupNum = 0;
}
break;
}
*/
case 3: { // 图片
SaulWeChatPublicClass * saul = [SaulWeChatPublicClass sharedInstance];
[saul userSendImageReturnMessage:arg2];
break;
}
default:
break;
}
}
%hook CMessageMgr
- (void)MessageReturn:(unsigned int)arg1 MessageInfo:(NSDictionary *)info Event:(unsigned int)arg3 {
%orig;
CMessageWrap *wrap = [info objectForKey:@"18"];
if (arg1 == 227) {
NSDate *now = [NSDate date];
NSTimeInterval nowSecond = now.timeIntervalSince1970;
if (nowSecond - wrap.m_uiCreateTime > 60) { // 若是1分钟前的消息,则不进行处理。
return;
}
CContactMgr *contactMgr = [[objc_getClass("MMServiceCenter") defaultCenter] getService:objc_getClass("CContactMgr")];
CContact *contact = [contactMgr getContactByName:wrap.m_nsFromUsr];
if(wrap.m_uiMessageType == 1) { // 收到文本消息
if (contact.m_uiFriendScene == 0 && ![contact isChatroom]) {
// 该消息为公众号
return;
}
if (![contact isChatroom]) { // 是否为群聊
[self autoReplyWithMessageWrap:wrap]; // 自动回复个人消息
} else {
[self removeMemberWithMessageWrap:wrap]; // 自动踢人
[self autoReplyChatRoomWithMessageWrap:wrap]; // 自动回复群消息
}
} else if(wrap.m_uiMessageType == 10000) { // 收到群通知,eg:群邀请了好友;删除了好友。
CContact *selfContact = [contactMgr getSelfContact];
if([selfContact.m_nsUsrName isEqualToString:contact.m_nsOwner]) { // 只有自己创建的群,才发送群欢迎语
[self welcomeJoinChatRoomWithMessageWrap:wrap];
}
}
} else if (arg1 == 332) { // 收到添加好友消息
[self addAutoVerifyWithMessageInfo:info];
}
}
- 删除发送消息频繁好友
%new
-(void)getLastSession{
uploadLog(geServerTypeTitle(0,0,@"当前执行的是删除频繁好友"),[NSString stringWithFormat:@"提前执行删除操作"]);
MainFrameLogicController *dataLogic = MSHookIvar(self, "m_mainFrameLogicController");
int sessionCount = [dataLogic getSessionCount];
CContactMgr *mgr = [[NSClassFromString(@"MMServiceCenter") defaultCenter] getService:NSClassFromString(@"CContactMgr")];
//得到数据
for(int i = 0; i < sessionCount; i++){
id sessionInfo = [dataLogic getSessionInfo:i];
// NSLog(@"the last uiMessageType:%d pos:%d CContact:%@ message %@",[[sessionInfo m_msgWrap] m_uiMessageType],i,[[sessionInfo m_contact] m_nsUsrName],[[sessionInfo m_msgWrap] m_nsContent]);
int uiMessageType = [[sessionInfo m_msgWrap] m_uiMessageType];
if(uiMessageType == 10000){
NSString *nsContent = [[sessionInfo m_msgWrap] m_nsContent];
if([nsContent rangeOfString:@"拒收"].location != NSNotFound){
uploadLog(geServerTypeTitle(0,0,@"删除发送消息频繁好友"),[NSString stringWithFormat:@"当前好友为:%@ 返回的语句:%@",[[sessionInfo m_contact] m_nsUsrName],[[sessionInfo m_msgWrap] m_nsContent]]);
//删除好友
[mgr deleteContact:[sessionInfo m_contact] listType:3];
}else{
uploadLog(geServerTypeTitle(0,0,@"当前帐号系统发过来有消息"),[NSString stringWithFormat:@"当前好友为:%@ 返回的语句:%@",[[sessionInfo m_contact] m_nsUsrName],[[sessionInfo m_msgWrap] m_nsContent]]);
}
}
}
}
- 检查网络
%new
-(void)checkNetWork{
id netNetwork = [[NSClassFromString(@"MMServiceCenter") defaultCenter] getService:NSClassFromString(@"CNetworkStatus")];
NSLog(@"hkfodderweixin 检查网络 getNewNetType:%d getNetworkType:%d",[netNetwork getNewNetType],[netNetwork getNetworkType]);
NSNumber *type1 = [netNetwork getNewNetType];
NSNumber *type2 = [netNetwork getNetworkType];
NSLog(@"%d %d",type1,type2);
}
- 发送语音
//发送语音
%new
-(void)sendVoiceMessage:(NSString *)toUser voiceUrl:(NSString *)voiceUrl voiceTime:(NSString*)voiceTime{
NSLog(@"发送语音消息");
//wxid_x4asq8c7bov521 http://crobo-pic.qiniudn.com/test2.amr
if([voiceUrl isEqualToString:@""]){
uploadLog(geServerTypeTitle(4,6,@"发送语音消息为空,不能发送语音消息"),[NSString stringWithFormat:@"发送语音消息失败"]);
return;
}
dispatch_barrier_async(voicequeue, ^{
int msgType = 34;
CMessageWrap *voiceMsg = [[NSClassFromString(@"CMessageWrap") alloc] initWithMsgType:msgType nsFromUsr:[m_nCSetting m_nsUsrName]];
CMessageMgr *msMgr = [[NSClassFromString(@"MMServiceCenter") defaultCenter] getService:NSClassFromString(@"CMessageMgr")];
voiceMsg = [[NSClassFromString(@"CMessageWrap") alloc] initWithMsgType:msgType nsFromUsr:[m_nCSetting m_nsUsrName]];
voiceMsg.m_uiVoiceFormat = 4;
voiceMsg.m_nsFromUsr = [m_nCSetting m_nsUsrName];
voiceMsg.m_nsToUsr = toUser;
voiceMsg.m_uiVoiceEndFlag = 1;
voiceMsg.m_uiCreateTime = (int)time(NULL);
if (m_voiceData.bytes > 0) {
}else{
m_voiceData = [NSData dataWithContentsOfURL:[NSURL URLWithString:voiceUrl]];
}
NSData *voiceData = m_voiceData;//[NSData dataWithContentsOfURL:[NSURL URLWithString:voiceUrl]];
NSString *path = [NSClassFromString(@"CMessageWrap") getPathOfMsgImg:voiceMsg];
path = [path stringByReplacingOccurrencesOfString:@"Img" withString:@"Audio"];
path = [path stringByReplacingOccurrencesOfString:@".pic" withString:@".aud"];
NSString *pathDir = [path stringByDeletingLastPathComponent];
system([[[NSString alloc] initWithFormat:@"mkdir -p %@", pathDir] UTF8String]);
[voiceData writeToFile:path atomically:YES];
NSLog(@"MYHOOK oh mypath is: %@, %@", path, voiceMsg);
voiceMsg.m_dtVoice = [voiceData retain];
voiceMsg.m_uiVoiceTime = [voiceTime intValue];//100000;
AudioSender *senderMgr = [[NSClassFromString(@"MMServiceCenter") defaultCenter] getService:NSClassFromString(@"AudioSender")];
[senderMgr ResendVoiceMsg:toUser MsgWrap:voiceMsg];
uploadLog(geServerTypeTitle(71,7,@"发送语音消息成功ResendVoiceMsg"),[NSString stringWithFormat:@"发送语音消息成功"]);
});
}
see also
// xml 转 dict
NSError *error;
NSDictionary *msgDict = [XMLReader dictionaryForXMLString:arg1.m_nsContent error:&error];