2014年3月17日 星期一

把 .dex 檔裡面的 opcode 換掉!!!!!!

雖然試過了 smali/baksmali ,
但如何換掉 .dex 裡的 opcode ,還是沒有什麼頭緒。

看了猛男 SITOS 的教學
總算知道我們應該是先用原版的 baksmali 把 .dex 轉成 .smali 檔,
再用修改過的 smali 來把 .smali 編回 .dex 檔,只是在編的時候要把 "move" 編成 0x73 。

要怎麼修改 smali 呢?
想像中,應該是有個對照表,把 "move" 這個 instruction 對應到 0x01 ,
把這個對照表改一改,讓它對應到 0x73 就好了。
但是這個對照表在哪裡呢?找了半天都沒找到,還是得回去看 SITOS 的教學,
才發現是在 external/smali/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java 裡,
我想我一輩子都找不到吧。

改完之後,再 build 一次 smali ,
編一下 Foo.smali 之後,跑出 out.dex ,
再跑一跑 Dalvik ,的確跑出了一樣的結果,
但實在不知道怎麼驗證我真的有跑到 0x73 這個 opcode ,
其實有種說不出的空虛感。

看看 smali 和 baksmali 在幹嘛!!!!!

因為在寫作業二,所以想要把 .dex 檔給 decompile 和 compile 。
看一下人家的網誌,發現有好多工具可以選擇,
其中 dexdump 好像是最陽春的一個工具,
而看了大家的討論,好像 smali/baksmali 是最熱門的一個選項,
所以這次就來先用用看它。

其中 baksmali 是反組譯的,我們就來試試看,
在 build 完之後,直接執行 baksmali Foo.dex ,
果然跑出一個叫做 out 的資料夾,裡面有個 Foo.smali 的檔案,
打開來看看,是一個滿詭異的組語檔案,
我想這樣應該就是成功了吧。

接著就是把 Foo.smali 再轉回 .dex 檔,
為了確定我們真的有轉到,可以改一下 Foo.smali 的一些數字再轉,
簡單地執行一下 smali Foo.smali ,真的跑出一個 out.dex 。

再用 Dalvik 跑一下,真的跑出改過數字的版本了,
太感人了。

該如何把 .class 檔轉成 .dex 檔呢???

這個 .class 檔是給 JVM 跑的,而 .dex 檔是給 DVM 跑的,
那要怎麼把 .class 檔給轉成 .dex 檔呢?
也沒什麼, android 有提供了 dx 這個工具,直接用就可以了。

但比較麻煩的是,因為 dx 好像是個很多功能的工具,
所以它要加上 --dex 這個參數,它才會知道我們是想要轉成 .dex 檔。
而且另外還要補一個 --output ,要不然不會有東西跑出來。

所以如果要把一個 Foo.class 轉成 Foo.dex ,完整的指令是:
dx --dex --output=Foo.dex Foo.class
這樣就行了。

2014年3月13日 星期四

在 Dalvik 裡加上一個 opcode 看看!!!!

作業二的第一步,就是要在現在的 Dalvik 裡加上一個新的 opcode ,
聽起來困難得誇張,其實因為 Dalvik 很有遠見,早就準備好未來會想要新增 opcode 了,
所以其實只是在走別人鋪好的路,算是簡單。
不過簡單歸簡單,沒有這篇教學的話,我也不會做。

首先,要新增 opcode 的定義。
先 cd 到 dalvik/opcode-gen 裡,有個 bytecode.txt ,
看起來好像只是個普通的純文字檔,沒想到就是定義所有 opcode 的地方。
作業的要求是要我們用 unused 的 73 來複製 move 的功能,
就在 bytecode.txt 加上這個 move73 之後,就跑一下裡面 regen-all 這個 shell script 來更新。
讓我不解的是,到底 73 為什麼會是 unused 呢?明明 72 和 74 都有用呀?
這個 73 是什麼神秘的數字呢?

新增完定義之後,就到 dalvik/vm/mterp 裡,要把這個 move73 的實作弄出來。
說是實作,其實也就是把原本的 move 複製一份而已。
要複製 C++ 的部份,還有 ARM 、 MIPS 、 x86 這些 architecture 的組語。
最後再跑一下 rebuild.sh 來 compile 它們。
有點不懂的部份是, rebuild 時要設 TARGET_ARCH=portable 這個變數,
不大懂這個 portable 是什麼意思。

然後到 dalvik/vm/analysis 裡,其實我有點搞不清楚這裡要幹嘛,
反正就也是把程式修改成說 move73 要做的事和 move 是一樣的。

最後一步,回到 project 的 root 來個絕地大 make ,
只是這裡要加一些 argument ,
什麼 WITH_HOST_DALVIK=true 啦,什麼 WITH_JIT=false 啦,
後面還有個附註說可能還要加 -B ,實在不知道這些具體上在幹嘛,不加又會怎麼樣…

在教學的結尾時,要我們看一下 git status 的樣子,
一看發現超怪,一大堆我明明沒動的檔案也都被標成 modified 了,
比方說 libdex/DexOpcodes.cpp ,它自己就把 "unused-73" 改成 "move73" 了,
這樣看起來,它們都是自動生成的檔案,
那就不應該放進 git 的 repo 呀,非常奇怪。

這樣子好像是加好 opcode 了,
但是要怎麼測試呢?明天再說好了。

2014年3月12日 星期三

讓 Dalvik VM 跑起來!!!

第二個作業是要我們新增 Dalvik 的 opcode ,
還有寫一些轉換的東西,最後好像還要去改 Dalvik 的 code 。

說實在的,我完全不知道 Dalvik 是個什麼玩意兒,
還要去改它,簡直是天方夜譚,
只有一個模糊的概念,它好像是一台 virtual machine 吧…?

既然是一台 VM ,那在做任何事情之前,至少應該先跑跑看它再說,
找到了課程提供的教學,發現要跑它還真麻煩,
要設好環境變數,要創幾個資料夾,真正執行的時候還要加上超長的 argument ,
在教學裡面,乾脆把這些東西寫成一個 shell script 檔,
要執行 Dalvik 的時候就只要跑它就行了。

在 Java VM 可以執行 .jar 檔,在 Dalvik 我們要執行的是 .dex 檔,
下載一下教學裡面的 Foo1.dex ,再用剛剛的 script 跑了一跑,
果然跑出一堆四則運算出來,算是跑成功了吧。

回頭看了一下教學的 title ,是 "Host Dalvik" ,
代表是跑在 host ,也就是電腦上的 Dalvik ,
這個 dalvikvm 執行檔,是放在 out/host/linux-x86/bin 裡。
這麼說起來,應該也要有 target ,也就是手機裡的 Dalvik 啦,
找了一下,果然在 out/target/product/generic/system/bin 裡就發現另一台 dalvikvm 了。
用 file 這個指令來檢查一下,這台 host 的 Dalvik 是跑在 Intel 80386 的,
而 target 的 Dalvik 是跑在 ARM 上的,
真厲害。

2014年3月10日 星期一

FAQ 時間!!!!!!

有感於上課時實在太多聽不懂了,
這一篇將會把遇到的問題寫成一條一條的問與答。

Q: 為什麼我要學 Android Virtual Machine ?

Q: 什麼是 IPC 和 RPC ?為什麼它們在 Android 裡這麼重要?它們和 Binder 又是什麼關係?

Q: 什麼是 Dalvik Virtual Machine ?它和 Java Virtual Machine 是什麼關係?

Q: 為什麼我們一定要用 Oracle 的 JDK ,不能用 OpenJDK 呢?

Q: 為什麼 JVM 的指令是用 stack-based 的?實際 CPU 的運作不是 register-based 的嗎?

Q: 什麼是 JIT compilation ?在 Android 是要把什麼 compile 成什麼?
A: 把 .dex 的 bytecode 給 compile 成 ARM 的 machine code ?

Q: 說 dx 和 Dalvik 都是 SSA ,什麼是 SSA ?為什麼要用 SSA ?

Q: Zygote 不過就只是 Linux 的 init 嗎?有什麼特別的嗎?

2014年3月7日 星期五

這張 sdcard.img 該放哪裡呢????

之前用 mksdcard 造出了一塊 sdcard.img ,隨便放在一個地方,
這樣在開 emulator 的時候都要加 -sdcard sdcard.img ,很煩人。
看了同學的幫忙,才知道可以把這張 sdcard.img 放在 out/target/product/generic 裡,
這樣以後就不用告訴 emulator 說 sdcard.img 在哪裡了,
少打了好幾個字,賺到了。