android re basic

By xia0

Android系统简介

文件目录

目录 说明
/system/app 预装的app(.apk)文件,如Alarm Clock, Browser, Contacts, Maps
/system/framework Android系统的核心库,有core.jar, framework-res.apk, com.google.android.gtalkservice.jar
/data/app 用户安装的app(.apk)文件
/data/data/app-package-name Context.openFileOutput()创建的文件

adb使用介绍

命令 说明
adb devices 列举连接到电脑
adb push local remote 可以copy本机文件到手机
adb pull remote local 可以copy手机文件到本机
adb shell 获得shell
adb install apk-file 安装
adb -s device-serialnum 指定某台设备
adb shell getprop ro.build.version.release 获取系统版本
adb shell getprop ro.build.version.sdk 获取系统api版本
adb -d 唯一指定连接的设备
adb -d shell getprop ro.product.cpu.abi 查看cpu型号

apk文件结构

文件或目录 说明
AndroidManifest.xml 一个清单文件,它描述了应用的名字、版本、权限、注册的服务等信息
assets文件夹 存放资源文件的目录
classes.dex java源码编译经过编译后生成的dalvik字节码文件,主要在Dalvik虚拟机上运行的主要代码部分
lib文件夹 存放ndk编译出来的so文件
META-INF文件夹 1.该目录下存放的是签名信息,用来保证apk包的完整性和系统的安全性
2.CERT.RS 保存着该应用程序的证书和授权信息
3.CERT.SF 保存着SHA-1信息资源列表 4.MANIFEST.MF 清单信息
res文件夹 存放资源文件的目录
resources.arsc 编译后的二进制资源文件

xposed

安装

手机端需要安装xposed框架

电脑端需要去https://jcenter.bintray.com/de/robv/android/xposed/api/下载依赖的jar包手动依赖,或者

compileOnly 'de.robv.android.xposed:api:82'让gradle去自动下载依赖。这两种方式不能同时使用。不然会编译出来的apk不能被xposed框架加载。

将两个jar包放入libs目录下

在build.gradle文件中添加以下

dependencies {
    compileOnly 'de.robv.android.xposed:api:82'
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

禁用instant run

AndroidManifest.xml中写入以下标识为xposed模块

<meta-data
    android:name="xposedmodule"
    android:value="true" />
<meta-data
    android:name="xposeddescription"
    android:value="desciption for the xposed module" />
<meta-data
    android:name="xposedminversion"
    android:value="53" />

创建assets文件夹并创建xposed_init的txt文件,里面按行写入hook类的全路径

com.xia0.crackmehooker.Hooks
使用
public class Hooks implements IXposedHookLoadPackage {

    final  String packageName = "com.xia0.crackmehooker";


    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam)  throws Throwable {

        if (loadPackageParam.packageName.equals(packageName)) {
            XposedBridge.log("[xia0] ===================hook=============");

            Class clazz = loadPackageParam.classLoader.loadClass("com.xia0.crackmehooker.MainActivity");

            XposedHelpers.findAndHookMethod(clazz, "toastMessage", new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {

                    param.setResult("you has been hooked");
                }
            });

        }
    }
}

代码很简单,无解释。

hook多dex或动态load的dex
XposedHelpers.findAndHookMethod(ClassLoader.class, "loadClass", String.class, 
                                new XC_MethodHook() {
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        if (param.hasThrowable()) return;
        Class<?> cls = (Class<?>) param.getResult();
        String name = cls.getName();
        if (name.contains("StringScriptSource")) {
            XposedBridge.log("[xia0]: load class "+ name);
            XposedBridge.hookAllMethods(cls, "getScript",new XC_MethodHook() {

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws 
                  Throwable {
                    // TODO
                    super.afterHookedMethod(param);

                    String ret = (String) param.getResult();

                    XposedBridge.log("[xia0]: hook result :\n"+ (String) ret);
                }
            } );
        }
    }
});

原理就是hook classLoader的loadClass方法,然后再去hook目标class,这时候就能解决hook的时候class不存在的问题。

jni编程

java文件

package com.xia0.jni;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    public TextView textview;
    public Button button;

    static {
        System.loadLibrary("ndktest");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.button = (Button) findViewById(R.id.button);
        this.textview = (TextView) findViewById(R.id.text);


        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, stringFromJni(),         Toast.LENGTH_SHORT).show();
                textview.setText(stringFromJni());
            }
        });
    }

    public native String stringFromJni();

}

C++文件

native.h

#ifndef NDK_CORE_H
#define NDK_CORE_H

#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))

#include <jni.h>
#include <stdlib.h>

__BEGIN_DECLS

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved);
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved);


__END_DECLS

#endif //TEXT_HELLO_H

native.cpp

#include "native.h"

jstring returnString(JNIEnv *env,jobject jobj){
  char* str = "I come from C++";
  return env->NewStringUTF(str);
}

static JNINativeMethod gMethods[] = {
    {"stringFromJni","()Ljava/lang/String;",(void *)returnString }
};

JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *vm,void *reserved) {
  JNIEnv *env;
  if (vm->GetEnv((void **) &env,JNI_VERSION_1_6) != JNI_OK){
    return JNI_ERR;
  }

  jclass javaClass = env->FindClass("com/xia0/jni/MainActivity");
  if (javaClass == NULL){
    return JNI_ERR;
  }
  if (env->RegisterNatives(javaClass,gMethods,NELEM(gMethods)) < 0) {
    return JNI_ERR;
  }

  return JNI_VERSION_1_6;
}

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndktest

LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_SRC_FILES := native.cpp

include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_ABI := armeabi-v7a x86
APP_PLATFORM := android-16
APP_STL := c++_shared
APP_OPTIM := debug
  • 打开terminal,cd src/main/jni文件夹中,然后执行ndk-build
  • 在项目名称的右键点击Link C++ Project with Gradle ,选择ndk-build,指定Android.mk文件路径
java 符号 c++
boolean Z jboolean
byte B jbyte
char C jchar
short S jshort
int I jint
long J jlong
float F jfloat
double D jdouble
void V
objects对象 Lfully-qualified-class-name; jobject
Arrays数组 [array-type jintArray

重打包

签名

生成keystore

keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000

签名apk

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore my_application.apk alias_name

验证签名

jarsigner -verify -verbose -certs my_application.apk

zip

zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk

调试

  • jdb

    在AndroidManifest.xml的application中添加android:debuggable="true"

    mprop

    BDOpener

    参考

    adb shell am start -D -n com.test.id/.MainActivity
    adb -d forward tcp:29882 jdwp:app_pid
    jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=29882
    
  • ida

    adb push dbgsrv/android_server /data/local/tmp
    ./android_server
    
    adb forward tcp:23946 tcp:23946
    
  • lldb

    platform select remote-android
    adb push lldb-server /data/local/tmp/
    adb shell /data/local/tmp/lldb-server platform --server --listen unix-abstract:///data/local/tmp/debug.sock
    
    platform select remote-android
    platform connect unix-abstract-connect:///data/local/tmp/debug.sock
    

刷机/root/xposed

Unlock bootloader

https://developers.google.com/android/images下载google原生镜像

adb reboot bootloader
fastboot flashing unlock
fastboot reboot

fastboot boot twrp-3.2.3-0-blueline.img  // boot TWRP

注意点:

常见资源/索引