Help us understand the problem. What is going on with this article?

iOSデバイスのチップセット情報をプログラムから取得する

More than 3 years have passed since last update.

自分のiPhone6s or 6s+のA9チップがサムスン製かTSMC製かを調べる(バッテリーの持ちが違うらしい)のがタイムラインで流行っていて、その方法として下記記事がシェアされてました。

シリアル番号とかから判断するのかなと思いつつ記事を読んでみると、AppStoreに出ているアプリを使って判定するとのこと。なるほど、ストアに出てるということは合法的に(Private API を使うことなく)プログラムからチップ情報を取得可能 ということなので、どうやってるんだろうと思いつつ、同日に見つけた GitHub の Trending で見かけた「CPU-Identifier」というOSSを思い出しました。

中身を見てみると、次のような実装になってました。

CPU-Identifier」の実装内容

dlfcn.h をインクルード

#include <dlfcn.h>

(CPU-Identifier では sysctl.h, resource.h, vm.h もインクルードしているが、本記事でピックアップする範囲では不要)

libMobileGestalt.dylib をロード

まず、dlopen() (ダイナミックライブラリをロードしてそのハンドラを返す関数)を使って /usr/lib/libMobileGestalt.dylib をロードします。

void *gestalt = dlopen("/usr/lib/libMobileGestalt.dylib", RTLD_GLOBAL | RTLD_LAZY);

libMobileGestalt.dylib は、UDID、ディスク使用量、デバイスバージョン等のシステム情報を取得するのに使われるライブラリ、とのことです。

libMobileGestalt is a library that can be used to get various system values such as the UDID, disk usage, device version and much more.

"MGCopyAnswer"がロードされたメモリアドレスを取得

次に、dlsym() を使って、"MGCopyAnswer" というシンボルがロードされたメモリアドレスを取得します。

$MGCopyAnswer = dlsym(gestalt, "MGCopyAnswer");

ボードIDを取得

上の手順で取得したメモリアドレスを格納した MGCopyAnswer は、MobileGestalt.h にて次のように定義されています。

CFPropertyListRef MGCopyAnswer(CFStringRef property);

で、この CFPropertyListRef から、"HardwarePlatform" 情報を次のように取り出します。

CFStringRef boardID = (CFStringRef)$MGCopyAnswer(CFSTR("HardwarePlatform"));

CFStringRef は Toll-Free Bridged なので、(__bridge NSString *)boardID とするだけで NSString にキャストできます。

この「ボードID」が 6s / 6s Plus だと "s8000" か "s8003" になるので、それぞれ Samsung 製、TSMC 製と判定できます。

if ([(__bridge NSString *)boardID isEqualToString:@"s8000"]) {
    manufactory.text = @"Samsung";
    isA9 = YES;
    imageName = @"A9";
}
if ([(__bridge NSString *)boardID isEqualToString:@"s8003"]) {
    manufactory.text = @"TSMC";
    isA9 = YES;
    imageName = @"A9";
}

ちなみに僕の iPhone 6s は見事に「ハズレ」とされる Samsung 製でした。。

a9.jpg

A9以外のチップの判定

さらに「CPU-Identifier」では下記コードのようにA9チップ以外も判定できるように実装されています。

NSString* str2Cmp = [(__bridge NSString *)boardID lowercaseString];
if ([str2Cmp hasPrefix:@"s5l8960"] || [str2Cmp hasPrefix:@"s5l8965"]){
    imageName = @"A7";
}else if ([str2Cmp hasPrefix:@"t7000"]){
    imageName = @"A8";
}else if ([str2Cmp hasPrefix:@"t7001"]){
    imageName = @"A8X";
}else if ([str2Cmp hasPrefix:@"s5l8950"]){
    imageName = @"A6";
}else if ([str2Cmp hasPrefix:@"S5L8955"]){
    imageName = @"A6X";
}else if ([str2Cmp hasPrefix:@"s5l8940"] || [str2Cmp hasPrefix:@"s5l8942"] ){
    imageName = @"A5";
}else if ([str2Cmp hasPrefix:@"s5l8945"]){
    imageName = @"A5X";
}else if ([str2Cmp hasPrefix:@"s5l8930"]){
    imageName = @"A4";
}

別の判定方法

ここまでやってみてやっと気付いたのですが、冒頭の参考記事で紹介されているアプリとは判定方法が違うようです。記事内のアプリでは、下記のように判定を行っていました。

  • iPhone 6s
    • N71AP:Samsung製
    • N71mAP:TSMC製
  • iPhone 6s Plus
    • N66AP:Samsung製
    • N66mAP:TSMC製

ハードについて全然詳しくないので、s8000が何を指していてN71APが何を指しているかとか正直よくわからないのですが、とりあえずこの "N71AP" をどうやったら取得できるのか、MGCopyAnswer から色々取得して見てみました。

CFStringRef modelNumber = (CFStringRef)$MGCopyAnswer(CFSTR("ModelNumber"));
NSLog(@"modelNumber:%@", modelNumber);

CFStringRef chipId = (CFStringRef)$MGCopyAnswer(CFSTR("ChipID"));
NSLog(@"chipId:%@", chipId);

CFStringRef hwModel = (CFStringRef)$MGCopyAnswer(CFSTR("HWModelStr"));
NSLog(@"hwModel:%@", hwModel);

iPhone6sでの実行結果:

modelNumber:MKQT2
chipId:32768
hwModel:N71AP

出ました、冒頭記事(内のアプリ)は "HWModelStr" を用いた判定方法のようです。

ちなみにこの N71AP というのは、ググってみると Samsung 製 A9 プロセッサを使用している iPhone 6s そのもののことを指しているようです。

This is the iPhone 6s which uses the Samsung A9 processor.

https://www.theiphonewiki.com/wiki/N71AP

これって合法?(このコード入りで審査通る?)

冒頭で、ストアにも出せる、と書きましたが、実際のところ怪しいかもしれません。下記記事ではこの「CPU-Identifier」作者の方が配布している野良アプリを使用する方法を紹介していて、

ここでは、

AppStoreで配布出来るものではないため

という記述もあります。

まぁ作者の方は単に面倒なのでこういう配布方法を取ったということは十分に考えられますが、万が一ストアに出すアプリでこの方法でハードウェア情報にアクセスしたい場合は、Appleのガイドライン等をよく読み自己責任でお願いいたします。

(たとえばシリアル番号とかUDIDも取れてしまうので、こういうのをサーバーに送ったりするアプリはアウトかと)

CFStringRef SNumber = MGCopyAnswer(CFSTR("SerialNumber"));
NSLog (@"Serial Number : %@", SNumber);

CFStringRef UDNumber = MGCopyAnswer(CFSTR("UniqueDeviceID"));
NSLog (@"UniqueDeviceID : %@", UDNumber);
shu223
フリーランスiOSエンジニア 著書:『iOS×BLE Core Bluetooth プログラミング』『Metal入門』『実践ARKit』『Depth in Depth』『iOSアプリ開発 達人のレシピ100』他 GitHubの累計スター数24,000超
http://shu223.hatenablog.com/
engineerlife
技術力をベースに人生を謳歌する人たちのコミュニティです。
https://community.camp-fire.jp/projects/view/280040
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away