5

Objective-Cで書かれた静的ライブラリを作成しようとしています。このライブラリの利用者からすべての実装の詳細を隠したいと思います。この例では、「OneThing」オブジェクトは、「SecretThing」など、ライブラリ内の他の機能を使用します。これは、ライブラリ内の多くのもので使用される可能性があります(OneThing内で非表示にすることはできません)。ただし、ライブラリのユーザーに、OneThingがSecretThingを使用していることや、.aファイルを調べてもSecretThingが存在することを確認したくありません。

@interface OneThing
+ (void) do;
@end
@interface SecretThing
+ (void) undo;
@end
@implementation OneThing
+ (void) do
{
    [SecretThing undo];
}
@end
@implementation SecretThing
+ (void) undo { }
@end

これをコンパイルして、シンボルテーブルを調べると:

% cc -c onething.m
% nm onething.o | grep Thing
0000000000000000 t +[OneThing do]
00000000000002f8 s +[OneThing do].eh
0000000000000040 t +[SecretThing undo]
0000000000000320 s +[SecretThing undo].eh
0000000000000078 S _OBJC_CLASS_$_OneThing
0000000000000050 S _OBJC_CLASS_$_SecretThing
00000000000000a0 S _OBJC_METACLASS_$_OneThing
00000000000000c8 S _OBJC_METACLASS_$_SecretThing
0000000000000128 s l_OBJC_$_CLASS_METHODS_OneThing
00000000000001d8 s l_OBJC_$_CLASS_METHODS_SecretThing
0000000000000190 s l_OBJC_CLASS_RO_$_OneThing
0000000000000240 s l_OBJC_CLASS_RO_$_SecretThing
0000000000000148 s l_OBJC_METACLASS_RO_$_OneThing
00000000000001f8 s l_OBJC_METACLASS_RO_$_SecretThing
% 

予想どおり、OneThingとSecretThingは同じように公開されています。これで、SecretThingのライブラリ内での使用を何らかの方法で解決し、OneThingのみを外部に公開することができれば素晴らしいと思います。私が働きたかったのはこれでした(試して管理する方法を1つだけ選びました):

% ld -r onething.o -exported_symbol "+[OneThing do]" -o onlyonething.o

私はこれが「+[OneThingdo]」をタイプ「T」、(テキストグローバル)としてマークし、それが「ストリップ」を生き残ることを望んでいました。そうではありません。これはある時点で機能すると思っていたので、これは私を悩ませます。ツールチェーンを更新したときに、動作が異なる新しいバージョンのld( "ld -v" == ld64-133.3)を入手した可能性があります。

リンカにソースを取得し、自分のやりたいことを実行するために独自の新しいフラグを作成することを除いて、私はアイデアがありません。私はただ愚かであり、これを容易にする理解できないことがあることを願っています。


回答では、メソッドのディスパッチを実行するには実行時に利用可能なすべてのリンケージ情報が必要なため、これは基本的に不可能であることが示唆されました。この実験はそれが真実ではないことを証明していると思います。

# Move OneThing and SecertThing into their own files, with their own .h
% cat c_api.m
#include "OneThing.h"

void one_thing_do()
{
    [OneThing do];
}
% cc -c c_api.c
% cat main.m
int main(int argc, char**argv)
{
    extern void one_thing_do();

    one_thing_do();
}
% cc main.m c_api.o onething.o secretthing.o -framework Foundation
% ./a.out
% ( runs to completion, no errors )

今、私たちは世界に見せたくない部分を隠そうとします:

% ld -r c_api.o onething.o secretthing.o -o strip_c_api.o -exported_symbol "_one_thing_do"
% strip -x c_strip_c_api.o
% nm strip_c_api.o
0000000000000118 s EH_Frame1
0000000000000098 s EH_Frame1
00000000000000d8 s EH_Frame1
                 U __objc_empty_cache
                 U __objc_empty_vtable
                 U _objc_msgSend
0000000000000000 T _one_thing_do
0000000000000130 s func.eh
00000000000000f0 s func.eh
00000000000000b0 s func.eh
0000000000000020 t l001
0000000000000060 t l002
0000000000000170 s l003
0000000000000190 s l004
00000000000001d8 s l005
0000000000000220 s l006
0000000000000240 s l007
0000000000000288 s l008
00000000000002f0 s l009
0000000000000318 s l010
0000000000000340 s l011
0000000000000368 s l012
% clang main.m strip_c_api.o -framework Foundation
% ./a.out
% nm a.out
0000000100001280 S _NXArgc
0000000100001288 S _NXArgv
0000000100001298 S ___progname
0000000100000000 T __mh_execute_header
                 U __objc_empty_cache
                 U __objc_empty_vtable
0000000100001290 S _environ
                 U _exit
0000000100000db0 T _main
                 U _objc_msgSend
0000000100000de0 T _one_thing_do
0000000100001000 s _pvars
                 U dyld_stub_binder
0000000100000d70 T start
4

3 に答える 3

6

これは、Objective-Cランタイムが動的に機能するため不可能です。ランタイムは、クラスをインスタンス化してメッセージを送信するためにこれらの情報を必要とするため、ライブラリを壊さずにこの情報を非表示にする方法は実際にはありません。

于 2012-07-26T19:06:45.627 に答える
3

AppleのDocumentaionから、いくつかの詳細:C++ランタイム環境プログラミングガイド

シンボルの可視性とObjective-C

Objective-CはCの厳密なスーパーセットであり、Objective-C++はC++の厳密なスーパーセットです。これは、CおよびC ++でのシンボルの可視性に関するすべての説明が、Objective-CおよびObjective-C++にも当てはまることを意味します。コンパイラフラグ、可視性属性、および可視性プラグマを使用して、Objective-Cコードファイル内のCおよびC++コードを非表示にすることができます。

32ビットOSXプロジェクトでは、これらの可視性コントロールは、コードのCまたはC++サブセットにのみ適用されます。これらはObjective-Cのクラスとメソッドには適用されません。Objective-Cのクラス名とメッセージ名は、リンカーではなくObjective-Cランタイムによってバインドされるため、可視性の概念はそれらに適用されません。ダイナミックライブラリで定義されたObjective-Cクラスまたはメソッドをそのライブラリのクライアントから隠すメカニズムはありません。

x86_64 OS XまたはiOS用にビルドする場合、シンボルの可視性はObjective-Cクラスに影響します。クラスを非表示にすることはセキュリティの万能薬ではありません。エンタープライズ開発者はObjective-Cランタイム呼び出しを使用して任意のクラスにアクセスできますが、リンク先のライブラリで可視性が非表示になっているクラスを直接参照すると、リンカーエラーが発生します。つまり、特定のクラスがライブラリまたはそのクラスで定義されている実行可能ファイルの外部で使用できるようにする場合は、適切なシンボルの可視性を確保する必要があります。

于 2012-07-30T20:04:38.293 に答える
0

これらを難読化する方法があります!NSInvocationまたはperformSelectorを使用して、メソッド呼び出しを呼び出すことができます。そうすれば、メソッド/クラス名を暗号化してから実行時に復号化して、呼び出すことができます。

于 2020-06-13T05:39:23.197 に答える