Japan Computer Emergency Response Team Coordination Center 電子署名者 : Japan Computer Emergency Response Team Coordination Center DN : c=jp, st=tokyo, l=chiyoda-ku, email=office@jpcert.or.jp, o=japan Computer Emergency Response Team Coordination Center, cn=japan Computer Emergency Response Team Coordination Center 日付 : 2014.07.22 11:35:58 +09'00' JEB Plugin 開発チュートリアル 第4回 JEB PluginからASTを扱う 一般社団法人JPCERTコーディネーションセンター
目次 第 0 回 JEB とは? 第 1 回 JEB Plugin とは 1. JEB Plugin の使い方 2. JEB Plugin の構造 3. JEB の UI を利用するための API 4. View と Signature 第 2 回 DEX ファイルの構造を理解する 1. DEX ファイルの構造 2. jeb.api.dex 3. クロスリファレンス第 3 回バイトコードについての理解 1. CodeItem 第 4 回 JEB Plugin から AST を扱う 1
AST とは 抽象構文木 Abstract Syntax Tree 言語 ( プログラム ) の意味に関係のないものを取り除きツリー構造で表したもの 2
JEB と AST JEB では DEX をデコンパイルして得られる Java コードが AST として内部的に管理されている JEB PluginからASTにアクセスするためのAPIが用意されている jeb.api.jebinstanc e getdecompiledclasstree(partial_sig) getinnterclasses() jeb.api.ast.class getdecompiledmethodtree(partial_sig) getfields() jeb.api.ast.field getmethods() jeb.api.ast.method getbody() jeb.api.ast.block Souce Code AST 3
AST の取得 JEB Plugin から AST を取得するには 事前に Java のコードにデコンパイルしておく必要がある JebUI.decompileClass() メソッドの取得 JebInstance.getDecompiledMethod(sig) jeb.api.ast.class.getmethods() Method のリストを取得 クラスの取得 JebInstance.getDecompiledClassTree(sig) 4
例題 1 AST クラス / メソッドを取得しよう jeb.api.ast.class の使い方を理解する 5
[ 例題 1] AST クラス / メソッドの取得 課題 Assembly View のキャレット位置のクラス (jeb.api.ast.class) を取得し 内包するフィールドとメソッドの一覧を表示する期待する出力結果 ヒント デコンパイルの実行 decompileclass() キャレット位置の Signature の取得 getcodeposition().getsignature() jeb.api.ast.class の取得 getdecompiledclasstree() メソッド / フィールド一覧の取得 6
例題 1 の解答例 DisplayAstClass.py 7
[ 解説 ] AST クラス / メソッドの取得 sig = view.getcodeposition().getsignature() print sig キャレット位置の Signature を取得する csig = re.sub(r'->.*$', '', sig) ui.decompileclass(csig, False) 取得した Signature を Class Signature に変換し クラスをデコンパイルする cls = jeb.getdecompiledclasstree(csig) print "target class: " + cls.gettype() print "[Method]" for m in cls.getmethods(): print " t" + m.getsignature() print "" print "[Field]" for f in cls.getfields(): print " t" + f.getsignature() Class Signature を使用して クラスを取得する メソッドを取得 フィールドを取得 8
AST のコードの取得 jeb.api.ast.method.getbody() このメソッドを使用するこ とで Block を取得できる jeb.api.jebinstance getdecompiledclasstree(partial_sig) getdecompiledmethodtree(partial_sig) jeb.api.ast.class getinnterclasses() getmethods() getfields() jeb.api.ast.method jeb.api.ast.field 階層図の中での getbody() の位置 getbody() jeb.api.ast.block メソッドのコード全体を Block として取得する 9
IElement すべての AST ノードのベースとなるインターフェイス IElement.getSubElements() AST の子ノードのリスト取得 IElement.replaceSubElements () AST の子ノードの置き換え <<interface>> IElement getsubelements() <<interface>> IElement <<interface>> IElement <<interface>> IElement 10
AST のクラス構造 <<interface>> IElement Statement NonStatement Assignment Break Call Compound Continue Block ForStm IfStm ArrayElt Constant Expression Identifier すべてのノードが Statement( 文ノード ) の NotStatement( 非文ノード ) のサブクラスで構成 Statement 文ノード Assignment: 値の代入 ( 例 str = abc ;) Call: メソッド呼び出し ( 例 str.startswiths( a ); ) NonStatement 非文ノード Expression: 式 ( 例 : a+b) 11
AST の要素を辿る IElement.getSubElements() では直下のノードしか取得できないが 再帰的に呼び出すことで すべてのノードを取得できる def traverse(elem): print elem. class. name for e in elem.getsubelements(): traverse(e) 12
例題 2 AST の traverse IElement.getSubElements() の使い方を理解する 13
[ 例題 2] AST の traverse 課題 Java View でキャレット位置のメソッドの AST を traverse する AST の各ノードのクラス名を表示する期待する出力結果 ヒント コードブロックの取得 : jeb.api.ast.method.getbody() IElement.getSubElements() element を受け取って 名前を表示するメソッドを作る def traverse(self, elem, depth=0): getsubelements() 再帰呼び出し 再帰呼び出しで depth を +1 する print( [%d] %s % (depth, class_name)) クラス名の取得 : obj. class. name 14
例題 2 の解答例 TraverseAst.py 15
[ 解説 ] AST の traverse sig = view.getcodeposition().getsignature() if sig in dex.getmethodsignatures(false): else: method = jeb.getdecompiledmethodtree(sig) self.traverse(method.getbody()) print "caret is not in method.: " + sig getsubelements() を再帰的に呼び出すメソッドに処理を投げる def traverse(self, elem, depth=0): print("%s[%d]%s" % (' '*depth, depth, elem. class. name )) for e in elem.getsubelements(): self.traverse(e, depth+1) getsubelements() は直下のノードしか取得できないので これを再帰的に呼び出すメソッドを作る 16
IElement を Traverse する限界 if 文 条件 true の時 false の時 IElement.getSubElements() で Traverse するだけでは限界がある 子ノードのリストが取得できるだけでそれぞれが何を表しているかまでは分からない 各クラスに実装されているメソッドで情報を取得する 17
ノード固有の情報へのアクセス方法 例 : IfStm(if 文 ) の場合 条件の取得 IfStm.getBranchPredicate(index) 条件一致した時の処理の取得 IfStm.getBranchBody(index) else 節の取得 IfStm.getDefaultBlock() 例 : Call( メソッド呼び出しの場合 ) 呼び出すメソッドの取得 Call.getMethod() 引数の取得 Call.getArguments() 条件は複数存在する可能性があるので index 指定する if(p) { b } else if(p1) { b1 } else { b2 } 18
例題 3 Method ノードの Signature の出力 jeb.api.ast.method.getsignature() の使い方を理解する 19
[ 例題 3] Method ノードの Signature の出力 課題 Java View でキャレット位置のメソッドの AST を traverse する AST の各ノードのクラス名を表示する 但し Traverse しているノードが Method の場合は [METHOD] Signature のように表示する期待する出力結果 ヒント Traverse 自体は先ほどと同じ オブジェクトのクラス判定 if isinstance(obj, jeb.api.ast.method): メソッドの Signature の取得 jeb.api.ast.method.getsignature() 20
例題 3 の解答例 TraverseAst2.py 21
[ 解説 ] Method ノードの Signature の出力 sig = view.getcodeposition().getsignature() if sig in dex.getmethodsignatures(false): else: method = jeb.getdecompiledmethodtree(sig) self.traverse(method.getbody()) print "caret is not in method.: " + sig def traverse(self, elem, depth=0): if isinstance(elem, jeb.api.ast.method): else: name = "[METHOD] %s" % elem.getsignature() name = elem. class. name print("%s[%d]%s" % (' '*depth, depth, name)) for e in elem.getsubelements(): self.traverse(e, depth+1) 取得したノードが jeb.api.ast.method のインスタンスかどうかチェックする 再帰的に呼び出す Method ノードの Signature を出力する 22
[ 参考 ] API リファレンス API のリファレンス http://www.android-decompiler.com/apidoc/ jeb.api Plugin から JEB にアクセスするためのクラスが含まれているパッケージ jeb.api.ast AST を使用するためのクラスが含まれているパッケージ jeb.api.dex JEB で開いた DEX ファイルを使用するためのクラスが含まれているパッケージ jeb.api.ui JEB の UI を操作するためのクラスが含まれているパッケージ 23
[ 参考 ] jeb.api.ast.statement 継承クラス Class Desc. Example Assignment 値の設定 str = abc ; Break ブレイク文 break; Call メソッド呼び出し str.equals( abc ); Compound Continue ブロック continue; Definition 変数定義 int a; Goto Label goto label; labelxx: Monitor syncronize monitor_enter(lock); monitor_exit(lock); New インスタンス生成 new Exception( aaa ); NewArray int[] a = {1,2,3}; Return return true; Throw 例外投入 throw e; 24
[ 参考 ] Compound (Statement) Class Example Block { } DoWhileStm do { } while(true); ForStm for(i=0; i<10; i++) { } IfStm if (xxx) { } else { } SwitchStm switch(xxx) { case 0:.. } TryStm try { } catch (Exception e) { } WhileStm while (true) { } 25
[ 参考 ] jeb.api.ast.nonstatement 継承クラス Class Desc. Example ArrayElt 配列要素へのアクセス array[index] Class Constant クラス 定数 Expression 式 a + 1 a * ((int)b foo()) Field Identifier InstanceField Method StaticField TypeReference フィールド 変数 インスタンスフィールド メソッド スタティックフィールド 型参照 ( オブジェクトのクラス確認 ) if (pet instanceof Dog) { } 26