这篇文章上次修改于 1129 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

title: 去APP升级弹窗
date: 2020/09/04 23:27:41
updated: 2020/09/05 01:23:00
permalink: remove-upgrade-dialog-and-rebuild-apk/

toc: true


环境和工具

  • kali linux 2019.4
  • frida-server 12.11.14
  • Android Studio 4.0.1 (android-studio-ide-193.6626763-linux.tar.gz)
  • apktool
  • objection
  • wallbreaker

步骤

开启frida-server

cd /data/local/tmp
./frida-server-12.11.11-android-arm64

搜索了解常见弹窗形式,例如android.app.AlertDialog

打开APP,等待出现弹窗

通过objection查找弹窗实例

android heap search instances android.app.AlertDialog

{% codeblock 查找弹窗实例 lang:bash %}
Class instance enumeration complete for android.app.AlertDialog
Hashcode Class toString()


170048846 android.app.AlertDialog android.app.AlertDialog@a22bd4e
{% endcodeblock %}

确定实现弹窗的类,然后通过wallbreaker插件查找实例

plugin load /root/.objection/plugins/Wallbreaker
plugin wallbreaker objectsearch android.app.AlertDialog

{% codeblock objectsearch lang:java %}

{% endcodeblock %}

通过wallbreaker对对象进行dump操作

plugin wallbreaker objectdump 0x3216

{% codeblock objectdump lang:java %}
package android.app

class AlertDialog {

                                                                                                                             
    /* static fields */                                                                                                      
    static int DISMISS; => 67
    static int CANCEL; => 68
    static String DIALOG_HIERARCHY_TAG; => android:dialogHierarchy
    static String TAG; => Dialog
    static String DIALOG_SHOWING_TAG; => android:dialogShowing
    static int SHOW; => 69
    static int THEME_DEVICE_DEFAULT_LIGHT; => 5
    static int THEME_TRADITIONAL; => 1
    static int THEME_DEVICE_DEFAULT_DARK; => 4
    static int THEME_HOLO_DARK; => 2
    static int LAYOUT_HINT_NONE; => 0
    static int THEME_HOLO_LIGHT; => 3
    static int LAYOUT_HINT_SIDE; => 1

    /* instance fields */
    int shadow$_monitor_; => -1977434802
    Class shadow$_klass_; => [0x30b6]: class android.app.AlertDialog
    DialogInterface$OnKeyListener mOnKeyListener; => null
    Message mShowMessage; => null
    boolean mShowing; => true
    boolean mCancelable; => true
    WindowManager mWindowManager; => [0x3082]: android.view.WindowManagerImpl@958a77c
    ActionMode mActionMode; => null
    boolean mCanceled; => false
    Handler mHandler; => [0x328a]: Handler (android.os.Handler) {3af4805}
    Runnable mDismissAction; => [0x32aa]: android.app.-$$Lambda$oslF4K8Uk6v-6nTRoaEpCmfAptE@271605a
    String mCancelAndDismissTaken; => null
    Message mCancelMessage; => null
    View mDecor; => [0x32ca]: DecorView@5423033[channel_main]
    ActionBar mActionBar; => null
    Message mDismissMessage; => null
    Activity mOwnerActivity; => null
    Context mContext; => [0x32ea]: android.view.ContextThemeWrapper@53da28b
    Handler mListenersHandler; => [0x32f6]: Handler (android.app.Dialog$ListenersHandler) {546bf68}
    int mActionModeTypeStarting; => 0
    Window mWindow; => [0x331a]: com.android.internal.policy.PhoneWindow@fe15f81
    SearchEvent mSearchEvent; => null
    boolean mCreated; => true
    AlertController mAlert; => [0x333a]: com.android.internal.app.AlertController@cd52826

    /* constructor methods */
    void AlertDialog(Context);
    void AlertDialog(Context, int);
    void AlertDialog(Context, int, boolean);
    void AlertDialog(Context, boolean, DialogInterface$OnCancelListener);

    /* static methods */
    static int identityHashCodeNative(Object);
    static int identityHashCode(Object);
    static void lambda$new$0(Dialog);
    static AlertController access$000(AlertDialog);
    static int resolveDialogTheme(Context, int);

    /* instance methods */
    int hashCode();
    void wait();
    void wait(long);
    void wait(long, int);
    void notify();
    void notifyAll();
    boolean equals(Object);
    Object clone();
    void finalize();
    Object internalClone();
    String toString();
    Class getClass();
    void openContextMenu(View);
    void onPanelClosed(int, Menu);
    boolean onPreparePanel(int, View, Menu);
    void create();
    void onBackPressed();
    boolean dispatchTouchEvent(MotionEvent);
    void hide();
    void show();
    boolean onTouchEvent(MotionEvent);
    View onCreatePanelView(int);
    ActionMode onWindowStartingActionMode(ActionMode$Callback);
    ActionMode onWindowStartingActionMode(ActionMode$Callback, int);
    void updateWindowForCancelable();
    boolean onKeyShortcut(int, KeyEvent);
    boolean onSearchRequested();
    boolean onSearchRequested(SearchEvent);
    void onCreate(Bundle);
    void onStop();
    void setCancelMessage(Message);
    void setDismissMessage(Message);
    boolean dispatchKeyEvent(KeyEvent);
    void onWindowFocusChanged(boolean);
    void dispatchOnCreate(Bundle);
    void dismiss();
    Object findViewById(int);
    boolean dispatchGenericMotionEvent(MotionEvent);
    void takeKeyEvents(boolean);
    void invalidateOptionsMenu();
    boolean onMenuOpened(int, Menu);
    boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent);
    ComponentName getAssociatedActivity();
    void openOptionsMenu();
    void onAttachedToWindow();
    boolean onKeyLongPress(int, KeyEvent);
    boolean dispatchTrackballEvent(MotionEvent);
    void onActionModeStarted(ActionMode);
    Activity getOwnerActivity();
    void setFeatureDrawable(int, Drawable);
    void sendShowMessage();
    ActionBar getActionBar();
    boolean requestWindowFeature(int);
    void onStart();
    void onCreateContextMenu(ContextMenu, View, ContextMenu$ContextMenuInfo);
    void onActionModeFinished(ActionMode);
    boolean onTrackballEvent(MotionEvent);
    void setFeatureDrawableUri(int, Uri);
    void unregisterForContextMenu(View);
    Object requireViewById(int);
    boolean onCreatePanelMenu(int, Menu);
    void setOnDismissListener(DialogInterface$OnDismissListener);
    boolean onContextItemSelected(MenuItem);
    void setTitle(CharSequence);
    void onWindowDismissed(boolean, boolean);
    void setOwnerActivity(Activity);
    void registerForContextMenu(View);
    boolean onGenericMotionEvent(MotionEvent);
    boolean takeCancelAndDismissListeners(String, DialogInterface$OnCancelListener, DialogInterface$OnDismissListener);
    boolean onKeyUp(int, KeyEvent);
    void onWindowAttributesChanged(WindowManager$LayoutParams);
    Bundle onSaveInstanceState();
    SearchEvent getSearchEvent();
    void cancel();
    View getCurrentFocus();
    boolean isShowing();
    void dismissDialog();
    void onOptionsMenuClosed(Menu);
    boolean onOptionsItemSelected(MenuItem);
    boolean onMenuItemSelected(int, MenuItem);
    Window getWindow();
    Context getContext();
    int getVolumeControlStream();
    void closeOptionsMenu();
    boolean onKeyDown(int, KeyEvent);
    boolean onPrepareOptionsMenu(Menu);
    void setCanceledOnTouchOutside(boolean);
    void sendDismissMessage();
    void onRestoreInstanceState(Bundle);
    boolean onCreateOptionsMenu(Menu);
    void setOnKeyListener(DialogInterface$OnKeyListener);
    void onDetachedFromWindow();
    void onContentChanged();
    void setFeatureDrawableAlpha(int, int);
    void setFeatureDrawableResource(int, int);
    void setOnShowListener(DialogInterface$OnShowListener);
    boolean onKeyMultiple(int, int, KeyEvent);
    void setVolumeControlStream(int);
    void addContentView(View, ViewGroup$LayoutParams);
    void setContentView(int);
    void setContentView(View);
    void setContentView(View, ViewGroup$LayoutParams);
    void setCancelable(boolean);
    boolean dispatchKeyShortcutEvent(KeyEvent);
    void setOnCancelListener(DialogInterface$OnCancelListener);
    LayoutInflater getLayoutInflater();
    void onContextMenuClosed(Menu);
    void setCustomTitle(View);
    void setButtonPanelLayoutHint(int);
    void setIcon(int);
    void setIcon(Drawable);
    ListView getListView();
    void setIconAttribute(int);
    void setButton2(CharSequence, DialogInterface$OnClickListener);
    void setButton2(CharSequence, Message);
    void setButton(int, CharSequence, DialogInterface$OnClickListener);
    void setButton(int, CharSequence, Message);
    void setButton(CharSequence, DialogInterface$OnClickListener);
    void setButton(CharSequence, Message);
    Button getButton(int);
    void setView(View);
    void setView(View, int, int, int, int);
    void setButton3(CharSequence, DialogInterface$OnClickListener);
    void setButton3(CharSequence, Message);
    void setMessage(CharSequence);
    void setInverseBackgroundForced(boolean);
    void setMessageHyphenationFrequency(int);
    void setMessageMovementMethod(MovementMethod);

}
{% endcodeblock %}

通过观察

AlertController mAlert; => [0x333a]: com.android.internal.app.AlertController@cd52826

然后objectdump 0x333a,确认结果与弹窗的内容相符

弹窗截图
objectdump 0x333a 结果

查看对象类的信息,确认就是这个类后,观察类被调用过程

由于是在APP启动时就会弹出,使用--startup-command注入watch class指令

objection -g com.hd.zhibo explore --startup-command "android hooking watch class android.app.AlertDialog"

watch class android.app.AlertDialog

可以看到调用了android.app.AlertDialog.onCreate这个方法

定位弹窗逻辑

对android.app.AlertDialog.onCreate方法进行watch

通过onCreate定位关键逻辑

这个时候发现了关键逻辑:com.zhibo.media.channel_main.update_show(Unknown Source:83)

使用apktool解包apk

apktool d zhibo.apk

修改smali代码逻辑实现不弹窗

定位到com.zhibo.media.channel_main.update_show,然后修改smali文件,修改部分略

使用apktool重新打包

apktool b zhibo/

使用keytool生成keystore文件

keytool -genkey -alias abc.keystore -keyalg RSA -validity 20000 -keystore abc.keystore

使用jarsigner对apk签名

jarsigner -verbose -keystore abc.keystore -signedjar new_zhibo.apk repack_zhibo.apk abc.keystore

安装新的apk进行验证