HEXA BLOG

プログラム

HEXA BLOGプログラム2019.2.20

配列の初期化子を取得してみた

こんにちは。大阪プログラマの澤野です。
最近「C#のアセンブリから配列の初期化子を取得する」ということをやったのでその方法を紹介します。
配列の初期化子を取得するにはImageBaseからFieldのオフセット値分ずらしたアドレスを見て取得すればよいのでは?
と考える方もいると思うのですが今回紹介するのはc#の「RuntimeHelpers.InitializeArray」を使用して初期化子を取得する方法です。

「RuntimeHelpers.InitializeArray」はArrayインスタンスとRuntimeFieldHandleを渡すことでArrayインスタンスに初期化子の値をコピーしてくれる関数です。
つまりArrayインスタンスを作成するための型と要素数さえ分かれば初期化子を取得することができるようになります。

今回は以下のサンプルコードを元に「test」インスタンスに入る値を取得してみます。

■サンプルコード

アセンブリから取得するのでバイトコードを見ていきます。
※Assemblyクラスから直接取得できる関数とかあるんですかね?知っている方がいたら教えてほしいです。

上記にあったサンプルコードをILSpyで解析すると以下のようになります。

■ILSpy結果

配列の初期化子を取得するために必要なのは
「IL_0002: newarr」 :Operandから配列の型を取得
「IL_0008: ldtoken」:OperandからRuntimeFieldHandleを取得
の二つになります。

「newarr」は分かりやすいので良いとして「ldtoken」について説明します。
「ldtoken」のOperandは型として配列のサイズを示していて以下のような情報を持っています。

■ldtokenのOperandの型情報

このOperandの型の[.size]が配列のサイズと一致するようで、配列の型とサイズを比較することで配列の要素数を取得することができます。
※[__StaticArrayInitTypeSize]から配列のサイズを取得できるのは経験則によるものなのでもしかしたら間違っているかもです。

以上のILSpyの結果をもとに初期化子を取得するコードを作成すると以下の通りになります。

■初期化子を取得するコード

これで配列の初期化子をアセンブリから取得できるようになります。
役に立つことなんてほとんどない知識ですが小ネタとして紹介させていただきました。
次回はもう少し需要のあることができたらなと思います。

※ブログを書きながら思いついたのですがnewarrする前に配列の要素数をldc.iで評価スタックに積むので、要素数を取得するだけなら__StaticArrayInitTypeSizeから取得する必要もないですね・・・

RECRUIT

大阪・東京共にスタッフを募集しています。
特にキャリア採用のプログラマー・アーティストに興味がある方は下のボタンをクリックしてください

RECRUIT SITE