iOS逆向:使用substrate及runtime进行hook

新的博客地址

@[toc]

前言

I 、hookMethod、ClassMethod

利用runtime.h进行hook


#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];

你可能感兴趣的:(逆向工程)