プライベートAPIの初期プローブ

4294 ワード

まず、プライベートAPIは研究のためだけで、AppStoreにはできないと表明し、アップルはreview guideでもプライベートAPIの使用を明確に禁止した。もちろん、もしあなたが企業版であれば、どうでもいいと思って、使ってもいいです。しばらくは企業版が発表したappが、アップルにプライベートAPIを使ったことが検出されたらどうなるか分かりません。


プライベートAPIを探索する際によく使われる方法をいくつか紹介します


1.frameworkのロード/アンインストール


多くのプライベートAPIはpublicのframeworkにありません.この場合、pathでframeworkをロードし、ロードが完了してからクラス名でオブジェクトを作成することができます.frameworkを動的にロードする方法を使用するには、手動でアンインストールする必要があります.このframeworkのクラスを使用するには、アンインストール操作の前に必要です.
#import 
//  framework
void *FTServicesHandle = dlopen("/System/Library/PrivateFrameworks/FTServices.framework/FTServices", RTLD_LAZY);
//  framework
dlclose(FTServicesHandle);

2.クラスを取得するすべての方法


このクラスを知っている場合は、メソッド名に基づいてメソッドを推測する機能を取るには、すべてのメソッドを知る必要があります.以下はruntimeでクラスのすべてのメソッドを取得するコードです.
#import 
unsigned int count;
Method *methods = class_copyMethodList([self class], &count);
for (int i = 0; i < count; i++) {
    Method method = methods[i];
    SEL selector = method_getName(method);
    NSString *name = NSStringFromSelector(selector);
    NSLog(@"->%@",name);
}

3.プライベートAPIを呼び出す方法


プライベートAPIを呼び出すとperformSelectorを直接通過できますが、performSelectorの制限を知っていて、値を返さないので、クラスの属性を手に入れたい場合は面倒です.以下、私の使い方を紹介します.今何が問題になるか分かりませんが、reviewを手伝ってください.多分、protocolを使って対応する属性と方法を定義し、携帯電話にインストールされているappを取得した例(iOS 11以前にのみ有効)を紹介します.関連するクラスは、LSApplicationWorkspaceとLSApplicationProxy、LSApplicationProxyの定義です.JTAppProtocolとLSApplicationWorkspace_JTAppProtocolの2つのプロトコルは、メソッドとプロパティがそれぞれ上の2つのクラスのメソッドとプロパティに対応し、名前と戻り値が一致しています.
@protocol LSApplicationProxy_JTAppProtocol 
+ (instancetype)applicationProxyForIdentifier:(NSString*)identifier;
@property (nonatomic, readonly) NSString    *localizedShortName;
@property (nonatomic, readonly) NSString    *localizedName;
@property (nonatomic, readonly) NSString    *bundleId;
@property (nonatomic, readonly) NSArray     *appTags;
@end

@protocol LSApplicationWorkspace_JTAppProtocol 
- (NSArray *)allInstalledApplications;
@end

使用方法も簡単で、idオブジェクトでLSApplicationProxyオブジェクトを受信し、idオブジェクトでLSApplicationWorkspaceオブジェクトを受信することで、このオブジェクトは自分で定義したprotocolに従うものと考えられ、直接メソッドや属性を呼び出したり、戻り値を保証したりすることができ、以下のように使用します.
@interface JTAppService ()
@property (nonatomic, strong) id  applicationWorkspace;
@end

@implementation JTAppService
+ (instancetype)sharedInstance {
    static dispatch_once_t once;
    static id sharedInstance;
    dispatch_once(&once, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init {
    if(self = [super init]) {
        self.applicationWorkspace = [[NSClassFromString(@"LSApplicationWorkspace") alloc] init];
    }
    return self;
}

- (NSArray *)readInstalledApplicationNames {
    NSArray *allInstalledApplications = [self.applicationWorkspace allInstalledApplications];
    NSMutableArray *allApplicationNames = [NSMutableArray arrayWithCapacity:allInstalledApplications.count];
    for(id proxy in allInstalledApplications) {
        if([[proxy appTags] indexOfObject:@"hidden"] != NSNotFound) {
            [allApplicationNames addObject:proxy.localizedName ?: proxy.localizedShortName];
        }
    }
    return allApplicationNames;
}
@end

4.コード混同


コード混同はプライベートAPI研究の一つではありませんが、多くの人がプライベートAPIの機能を見て、使いたいし、AppStoreのreview rejectにされたくないので、ホットアップデートで動的にコードをダウンロードするか、コード混同案を歩くか、混同も簡単です.方法はASCIIコードのchar型配列で混同したい文字列を表すことです.
#define LSApplicationWorkspaceChar (char[]){0x4c,0x53,0x41,0x70,0x70,0x6c,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x57,0x6f,0x72,0x6b,0x73,0x70,0x61,0x63,0x65,'\0'}
self.applicationWorkspace = [[NSClassFromString([NSString stringWithUTF8String:LSApplicationWorkspaceChar]) alloc] init];

まとめ


プライベートAPIの研究方法は簡単で、難点はどのように関連機能のframeworkとクラス名を見つけるかで、これらを知って、方法名と属性を取り出すことができて、それから1つの推測で、それから試して、すべての機種とシステムバージョンを互換する必要があって、比較的に大きい仕事量で、研究だけをすることを提案して、オンラインではありません.

リファレンス


[iOS]プライベートAPIの使用-焼雪残陽ZIKCellularAuthorization