Elfファイルのdynsymセクションとsymtabセクションの情報を利用して、シンボルの名前とアドレスを取得したいだと思います。
私は「Android-disassembler」という逆アセンブラを開発しています。現在このELFファイルのすべての.text
セクションをすべて逆アセンブルするには成功しました。
ところが、今はElfファイルのdynsymセクションとsymtabセクションの情報を利用して、シンボルの名前とアドレスを取得したいだと思います。
私はStack Overflowのいくつかの記事を見て、少し役立つ情報を見つけました。
これは、C言語で書かれていたので、
for (size_t header_index = 0; header_index < info->dlpi_phnum; header_index++)
{
/* Further processing is only needed if the dynamic section is reached */
if (info->dlpi_phdr[header_index].p_type == PT_DYNAMIC)
{
/* Get a pointer to the first entry of the dynamic section.
* It's address is the shared lib's address + the virtual address */
dyn = (ElfW(Dyn)*)(info->dlpi_addr + info->dlpi_phdr[header_index].p_vaddr);
/* Iterate over all entries of the dynamic section until the
* end of the symbol table is reached. This is indicated by
* an entry with d_tag == DT_NULL.
*
* Only the following entries need to be processed to find the
* symbol names:
* - DT_HASH -> second word of the hash is the number of symbols
* - DT_STRTAB -> pointer to the beginning of a string table that
* contains the symbol names
* - DT_SYMTAB -> pointer to the beginning of the symbols table
*/
while(dyn->d_tag != DT_NULL)
{
if (dyn->d_tag == DT_HASH)
{
/* Get a pointer to the hash */
hash = (ElfW(Word*))dyn->d_un.d_ptr;
/* The 2nd word is the number of symbols */
sym_cnt = hash[1];
}
else if (dyn->d_tag == DT_STRTAB)
{
/* Get the pointer to the string table */
strtab = (char*)dyn->d_un.d_ptr;
}
else if (dyn->d_tag == DT_SYMTAB)
{
/* Get the pointer to the first entry of the symbol table */
sym = (ElfW(Sym*))dyn->d_un.d_ptr;
/* Iterate over the symbol table */
for (ElfW(Word) sym_index = 0; sym_index < sym_cnt; sym_index++)
{
/* get the name of the i-th symbol.
* This is located at the address of st_name
* relative to the beginning of the string table. */
sym_name = &strtab[sym[sym_index].st_name];
symbol_names->push_back(string(sym_name));
}
}
/* move pointer to the next entry */
dyn++;
}
}
}
/* Returning something != 0 stops further iterations,
* since only the first entry, which is the executable itself, is needed
* 1 is returned after processing the first entry.
*
* If the symbols of all loaded dynamic libs shall be found,
* the return value has to be changed to 0.
*/
return 1;
}
(私はしたいのは、Javaコード)私自身、Javaで翻訳してみました。それは:
if (elf.dynamicTable != null)
{
StringBuilder sb=new StringBuilder();
Log.v(TAG, "size of dynamic table=" + elf.dynamicTable.length);
long strtab=0L; //pointer to the string table
long hash=0L;
int sym_cnt=0;
int i=0;
for (DynamicEntry de=elf.dynamicTable[0];;++i)
{
if (i >= elf.dynamicTable.length)
i = 0;
de = elf.dynamicTable[i];
DynamicEntry.Tag tag=de.getTag();
Log.v(TAG, tag.toString());
if (tag == null)
{
Log.v(TAG, "The tag is null");
break;
}
if (de.getTag().equals(DynamicEntry.Tag.NULL))
{
Log.v(TAG, "Tag is NULL tag");
break;
}
if (tag.equals(DynamicEntry.Tag.HASH))
{
hash = de.getValue();
/* Get a pointer to the hash */
// hash = (ElfW(Word*))dyn->d_un.d_ptr;
//
/* The 2nd word is the number of symbols */
// sym_cnt = hash[1];
//int hashvalue=fileContents[(int)hash]
sym_cnt = (fileContents[(int)hash + 1] << 8 | fileContents[(int)hash]);
Log.v(TAG, "Hash=" + hash + "cnt=" + sym_cnt);
}
else if (tag.equals(DynamicEntry.Tag.STRTAB))
{
strtab = de.getValue();
Log.i(TAG, "strtab=" + strtab);
}
else if (tag.equals(DynamicEntry.Tag.SYMTAB))
{
if (sym_cnt == 0 || strtab == 0)
{
continue;
}
long sym=de.getValue();
Log.i(TAG, "sym=" + sym);
// int sym_index=0;
for (int sym_index=0;sym_index < sym_cnt;sym_index++)
{
String sym_name=Elf.getZString(fileContents,(int)strtab + fileContents[(int)(sym + sym_index * 16)]); //get string that ends with NULL from byte array from the offset
sb.append(sym_name).append("\n");
Log.v(TAG, "sym_nmae=" + sym_name);
}
break;
}
}
info = sb.toString();
Log.i(TAG, "info=" + info);
}
期待し、上記のコードを実行させた結果がちょっと変です。
__cxa_finalize�
__cxa_atexit�
_ZN7_JNIEnv14GetObjectClassEP8_jobject�
__aeabi_unwind_cpp_pr1�
_ZN7_JNIEnv10GetFieldIDEP7_jclassPKcS3_� � Z� � it�
_unwind_cpp_pr1� etFieldIDEP7_jclassPKcS3_� � � �
__cxa_finalize� sEP8_jobject� object� eabi_unwind_cpp_pr1� nd_cpp_pr1� p_pr1� N7_JNIEnv10GetFieldIDEP7_jclassPKcS3_� ldIDEP7_jclassPKcS3_�
�(� Z� � � lize� cxa_atexit� 4GetObjectClassEP8_jobject� r1�
IEnv10GetFieldIDEP7_jclassPKcS3_� tFieldIDEP7_jclassPKcS3_�
DEP7_jclassPKcS3_� lassPKcS3_� � � � � � � � u� � � exit�
nv14GetObjectClassEP8_jobject� lassEP8_jobject� � ind_cpp_pr1�
ZN7_JNIEnv10GetFieldIDEP7_jclassPKcS3_� 0GetFieldIDEP7_jclassPKcS3_�
EP7_jclassPKcS3_� sPKcS3_�
変だと思います。
どのようにすればelfファイル内の関数の名前とアドレスを(ファイルオフセット)得とHashMap <Long, String>
に置くことができますか?
これを試してみたい方は、以下のファイルをダウンロードしてください(apk)
Githubリリース
テスト対象のファイル(hello-jni.so)
追記
自己回答しましたが、少しでもより良い回答にはお礼を授与します。私が使用される方法はDynsym
セクションで有効ですが、###Symtab
セクションはStringIndexOutOfBoundsException
で発生したり、ビットを切り捨てます。良い解決策があるかどうか確認してください。ありがとうございます。