美文网首页
抽离cycript里面的choose功能

抽离cycript里面的choose功能

作者: 我的发 | 来源:发表于2020-06-09 14:49 被阅读0次

众所周知,对于逆向或者日常开发dubug来说,ctcript是一个非常棒的工具。
尤其是它里面的choose 功能。
因为它的用法简单传一个类名或者地址进去就能找出内存中该类对象的实例
choose(ClassName)
如:

cy# choose(MMUINavigationController)
[#"<MMUINavigationController: 0x10d001200>",#"<MMUINavigationController: 0x10e0b7800>"]
cy# choose(UIButton)
[#"<FixTitleColorButton: 0x1115734d0; baseClass = UIButton; frame = (170 18; 130 47); clipsToBounds = YES; opaque = NO; autoresize = LM; layer = <CALayer: 0x111573320>>",#"<UIButton: 0x111575aa0; frame = (234 20; 86 49); opaque = NO; autoresize = LM; layer = <CALayer: 0x1115724a0>>",#"<FixTitleColorButton: 0x1105d1700; baseClass = UIButton; frame = (20 18; 130 47); clipsToBounds = YES; opaque = NO; autoresize = RM; layer = <CALayer: 0x1105d19e0>>"]

这么绝的工具如果能在项目工程或者插件里面用就好了。

那么就来抽离一下吧

ps:以下代码全部拷贝自大神的博客,且需要遵守GPL v3协议。大神博客

.h文件对外接口

#import <Foundation/Foundation.h>

@interface choose : NSObject

+ (NSArray *)choose:(NSString *)className;

@end

.m文件实现

#import "choose.h"
 
#include <objc/runtime.h>
#include <malloc/malloc.h>
#include <mach/mach.h>
#include <set>
 
struct choice {
    std::set<Class> query_;
    std::set<id> result_;
};

struct ObjectStruct {
    Class isa_;
};

static kern_return_t read_memory(task_t task, vm_address_t address, vm_size_t size, void **data) {
    *data = reinterpret_cast<void *>(address);
    return KERN_SUCCESS;
}

static Class * copy_class_list(size_t &size) {
    size = objc_getClassList(NULL, 0);
    Class * data = reinterpret_cast<Class *>(malloc(sizeof(Class) * size));
    for (;;) {
        size_t writ = objc_getClassList(data, (int)size);
        if (writ <= size) {
            size = writ;
            return data;
        }

        Class * copy = reinterpret_cast<Class *>(realloc(data, sizeof(Class) * writ));
        if (copy == NULL) {
            free(data);
            return NULL;
        }
        data = copy;
        size = writ;
    }
}

static void choose_(task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count) {
    choice * choice = reinterpret_cast<struct choice *>(baton);
    for (unsigned i = 0; i < count; ++i) {
        vm_range_t &range = ranges[I];
        void * data = reinterpret_cast<void *>(range.address);
        size_t size = range.size;
        if (size < sizeof(ObjectStruct))
            continue;

        uintptr_t * pointers = reinterpret_cast<uintptr_t *>(data);
#ifdef __arm64__
        Class isa = reinterpret_cast<Class>(pointers[0] & 0x1fffffff8);
#else
        Class isa = reinterpret_cast<Class>(pointers[0]);
#endif
        std::set<Class>::const_iterator result(choice->query_.find(isa));
        if (result == choice->query_.end())
            continue;
        size_t needed = class_getInstanceSize(*result);
        size_t boundary = 496;
#ifdef __LP64__
        boundary *= 2;
#endif
        if ((needed <= boundary && (needed + 15) / 16 * 16 != size) || (needed > boundary && (needed + 511) / 512 * 512 != size))
            continue;
        choice->result_.insert(reinterpret_cast<id>(data));
    }
}

@implementation choose

+ (NSArray *)choose:(NSString *)className{
    vm_address_t * zones = NULL;
    unsigned size = 0;
    kern_return_t error = malloc_get_all_zones(0, &read_memory, &zones, &size);
    assert(error == KERN_SUCCESS);

    size_t number;
    Class * classes = copy_class_list(number);
    assert(classes != NULL);

    choice choice;
    Class _class = NSClassFromString(className);
    for (size_t i = 0; i != number; ++i) {
        for (Class current = classes[i]; current != Nil; current = class_getSuperclass(current)) {
            if (current == _class) {
                choice.query_.insert(classes[I]);
                break;
            }
        }
    }
    free(classes);

    for (unsigned i = 0; i != size; ++i) {
        const malloc_zone_t * zone = reinterpret_cast<const malloc_zone_t *>(zones[I]);
        if (zone == NULL || zone->introspect == NULL)
            continue;
        zone->introspect->enumerator(mach_task_self(), &choice, MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], &read_memory, &choose_);
    }

#if __has_feature(objc_arc)
    NSMutableArray * result = [[NSMutableArray alloc] init];
#else
    NSMutableArray * result = [[[NSMutableArray alloc] init] autorelease];
#endif
    for (auto iter = choice.result_.begin(); iter != choice.result_.end(); iter++) {
        [result addObject:(id)*iter];
    }
    return result;
}
@end
需要注意的地方
  • choose.m必须要改为choose.mm , 因为引入的<set>是C++库

文件需要在MRC模式下运行,所以需要在Compile Sourceschoose.mmCompiler Flags设置为-fno-objc-arc

我已经将上面的代码写成demo,测试可用。

demo地址

image.png
题外话: FLEX里面也有类似的功能 链接在这在这

相关文章

  • 抽离cycript里面的choose功能

    众所周知,对于逆向或者日常开发dubug来说,ctcript是一个非常棒的工具。尤其是它里面的choose 功能。...

  • AOC(面向切面编程)(?)

    主要作用是把与核心业务逻辑模块无关的功能抽离出来,如日志统计、安全控制、异常处理等。把这些功能抽离出来之后,再通过...

  • 七 iOS逆向 - Cycript

    Cycript简介 Cycript基本使用 封装Cycript脚本 Cycript使用示例 一 Cycript简介...

  • css function

    功能样式:css function 概述 功能样式,从常用样式方法中抽离,按需使用,使用前请先阅读 CSS规范 中...

  • 在微信小程序里实现图片预加载组件

    该文章源于https://jdc.jd.com/archives/3820 将功能抽离成公用组件 实现这么一个功能...

  • iOS 底层原理 day02 SSH Cycript

    Cycript 常用语法 开启 Cycript 模式 Cycript Cycript -p 进程 ID Cycri...

  • 逆向App学习

    Cycript的基本语法 开启:cycript cycript -p 进程ID cycript -p 进程名称 取...

  • 抽离

    好像又一次陷入了恶性循环,这篇短文充满了负能量,别人喝酒怕喝醉,我嘛,是生怕自己不醉,消极,悲观,惊恐,麻痹,

  • 抽离

    忙碌而充实的星期天已经接近尾声,此时的哥哥还在完成最后的日记修订,而我抱着手机陪着弟弟一起记录今天的点点滴滴,文字...

  • 抽离

    我是一个非常有名的歌手,但是有一天在台上唱歌时耳塞掉了,我听见了自己的歌声,发现简直太难听了。我很失落地在路边散步...

网友评论

      本文标题:抽离cycript里面的choose功能

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