美文网首页
iOS 代码注入和HOOK

iOS 代码注入和HOOK

作者: 木扬音 | 来源:发表于2021-04-20 23:32 被阅读0次

    在中我们知道了可以通过重签名的方式将他人的IPA包安装在自己手机上,这篇文章我们来了解一下

    准备工作

    资料地址密码qbt2

    • 微信8.0.2IPA包
    • MachOView
    • yololib
    • class-dump

    首先我们使用上一篇iOS应用重签名中Xcode重签名的方式,来对微信8.0.2进行重签名,连接手机运行程序后,我们修改ViewController中添加代码会发现不起作用,是因为整个App(Mach-O)被替换了

    Mach-O 简单分析

    我们将上一步的可执行程序拖进MachOView中,进行分析,会得到一个可视化的Mach-O文件

    Mach-O文件

    我们知道在iOS中,可执行文件时通过dyld加载到内存中的,在Mach-O文件中,Load Commands会告诉dyld需要加载那些动态库

    image.png

    通过上面的分析,我们理论上是可以通过增加一个动态库来实现代码注入

    动态库代码注入

    添加动态库

    首先我们在重签名的项目中新建一个动态库,并添加一个load方法

    创建动态库
    然后Build一下,我们在微信的可执行程序的Frameworks中会找到我们刚新增的动态库
    image.png

    我们在运行一下程序,会发现load方法的代码并没执行。然后我们再用MachOView重新分析WeChat,会发现在Load Commands并没有刚刚新建的动态库,那么下面我要做就是将新建的动态库添加到Load Commands

    yololib修改Mach-O文件注入
    ./yololib WeChat Frameworks/HankHook.framework/HankHook
    
    yololib修改Mach-O文件

    我们再用MachOView重新分析WeChat,会发现我们新加的动态库已经添加进了Mach-O文件中


    Mach-O

    重新运行就可以了


    注入成功

    Dylib代码注入

    我们新建一个工程,使用iOS应用重签名中Xcode重签名的方式对WeChat进行重签名后,我们新建一个macOS的动态库

    macOS动态库
    修改macOS动态库的Base SDK为iOS,签名改为iOS Developer
    修改Base SDK
    修改签名

    在当前工程里添加动态库


    添加动态库

    同样的,我们在动态库中重写load方法


    重写load方法

    脚本执行

    更新原来Xcode中的脚本重新运行就可以了

    # ${SRCROOT} 它是工程文件所在的目录
    TEMP_PATH="${SRCROOT}/Temp"
    #资源文件夹,我们提前在工程目录下新建一个APP文件夹,里面放ipa包
    ASSETS_PATH="${SRCROOT}/APP"
    #目标ipa包路径
    TARGET_IPA_PATH="${ASSETS_PATH}/*.ipa"
    #清空Temp文件夹
    rm -rf "${SRCROOT}/Temp"
    mkdir -p "${SRCROOT}/Temp"
    
    
    
    #----------------------------------------
    # 1. 解压IPA到Temp下
    unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH"
    # 拿到解压的临时的APP的路径
    TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
    # echo "路径是:$TEMP_APP_PATH"
    
    
    #----------------------------------------
    # 2. 将解压出来的.app拷贝进入工程下
    # BUILT_PRODUCTS_DIR 工程生成的APP包的路径
    # TARGET_NAME target名称
    TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
    echo "app路径:$TARGET_APP_PATH"
    
    rm -rf "$TARGET_APP_PATH"
    mkdir -p "$TARGET_APP_PATH"
    cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH"
    
    
    
    #----------------------------------------
    # 3. 删除extension和WatchAPP.个人证书没法签名Extention
    rm -rf "$TARGET_APP_PATH/PlugIns"
    rm -rf "$TARGET_APP_PATH/Watch"
    
    
    
    #----------------------------------------
    # 4. 更新info.plist文件 CFBundleIdentifier
    #  设置:"Set : KEY Value" "目标文件路径"
    /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"
    
    
    #----------------------------------------
    # 5. 给MachO文件上执行权限
    # 拿到MachO文件的路径
    APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<`
    #上可执行权限
    chmod +x "$TARGET_APP_PATH/$APP_BINARY"
    
    
    
    #----------------------------------------
    # 6. 重签名第三方 FrameWorks
    TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks"
    if [ -d "$TARGET_APP_FRAMEWORKS_PATH" ];
    then
    for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"*
    do
    
    #签名
    /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK"
    done
    fi
    
    #代码注入
    ./yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/libHankHook.dylib"
    
    

    HOOK微信

    hook WeChat的注册、登录

    我们新建一个项目,通过上面的方式进行重签名和注入后,运行程序,在调试界面我们可以发现对应的登录和注册的ActionTarget

    调试WeChat

    或者我们也可以通过响应链找到对应的view


    响应链

    然后我们在新加的动态库中添加下面代码

    #import "InjectCode.h"
    
    #import <objc/runtime.h>
    
    @implementation InjectCode
    
    + ( void)load {
    
    Method oldMethod = class_getInstanceMethod(objc_getClass( "WCAccountLoginControlLogic"), @selector(onFirstViewRegister));
    
    Method newMethod = class_getInstanceMethod( self, @selector(my_register));
    
    method_exchangeImplementations(oldMethod, newMethod);
    
    }
    
    - ( void)my_register {
    
    NSLog( @"想注册吗?想注册先打钱!");
    
    }
    
    @end
    

    重新运行后,会打印出my_register中的信息

    窃取登录密码

    class-dump静态分析Mach-O

    终端命令

    ./class-dump -A WeChat
    ./class-dump -H WeChat -o ./headers/
    

    通过class-dump分析后,我们会得到OC的类列表和方法列表,然后我们用sublime工具进行全局查找对应的类

    搜索 WCAccountMainLoginViewController,里面有两个对象命名很像账号和密码的东西


    WCAccountMainLoginViewController

    搜索 WCAccountTextFieldItem


    WCAccountTextFieldItem

    搜索 WCBaseTextFieldItem,在里面找到了WCUITextField


    WCBaseTextFieldItem

    接下来我们来验证一下WCUITextField,在登录框中输入账号和密码,然后打开调试界面,通过valueForkey 找到登录密码

    valueForkey

    代码窃取登录密码

    方法交换
    +(void)load{
        //原始的Method
        Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext));
        
        //添加新方法!
        class_addMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(new_onNext), new_onNext, "v@:");
        //交换
        method_exchangeImplementations(onNext, class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(new_onNext)));
    }
    
    //新的IMP
    void new_onNext(id self,SEL _cmd){
        UITextField * pwd = (UITextField *)[[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"];
    
        NSLog(@"密码是:%@",pwd.text);
        //调用回原来的逻辑!!
        //调用原来的方法!
        [self performSelector:@selector(new_onNext)];
        //objc_msgSend();
        
    }
    
    方法替换
    +(void)load{
        //原始的Method
        Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext));
        old_onNext = class_replaceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext), new_onNext, "v@:");
       
    }
    //原来的IMP
    IMP (*old_onNext)(id self,SEL _cmd);
    //新的IMP
    void new_onNext(id self,SEL _cmd){
        UITextField * pwd = (UITextField *)[[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"];
    
        NSLog(@"密码是:%@",pwd.text);
        //调用回原来的逻辑!!
        //调用原来的方法!
        old_onNext(self,_cmd);
        //objc_msgSend();
        
    }
    
    getter和setter
    +(void)load{
        //原始的Method
        old_onNext = method_getImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)));
        method_setImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)), new_onNext);
       
    }
    //原来的IMP
    IMP (*old_onNext)(id self,SEL _cmd);
    //新的IMP
    void new_onNext(id self,SEL _cmd){
        UITextField * pwd = (UITextField *)[[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"];
    
        NSLog(@"密码是:%@",pwd.text);
        //调用回原来的逻辑!!
        //调用原来的方法!
        old_onNext(self,_cmd);
        //objc_msgSend();
        
    }
    

    相关文章

      网友评论

          本文标题:iOS 代码注入和HOOK

          本文链接:https://www.haomeiwen.com/subject/xzxolltx.html