android注入so或者dex

本程序分为32位和64位,以及so中加载apk(或者dex都可以)。

代码地址:点击下载

(一)so注入

32位和64位so注入代码几乎相同,因此仅以32位为例说明so注入的过程。

arm64-v8a架构可以兼容armeabi-v7a指令代码,测试机器是Huawei Nexus 6P Android 6.0,已经root(注入过程需要访问/proc/pid/cmdlind文件或者动态查找其他进程的模块和函数地址,因此需要root权限)。测试时,32位注入代码也可以在64位机器上运行,但是在编译时,需要将build.gradle中的ndk设置如下:

        ndk {
            abiFilters  'armeabi-v7a'
        }


否则,将会因为inject.c中如下指令集架构预处理导致的编译错误:

#if defined(__arm__)
int ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs)
{
    uint32_t i;
    for (i = 0; i < num_params && i < 4; i ++) {
        regs->uregs[i] = params[i];
    }

    //
    // push remained params onto stack
    //
    if (i < num_params) {
        regs->ARM_sp -= (num_params - i) * sizeof(long) ;
        ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)&params[i], (num_params - i) * sizeof(long));
    }

    regs->ARM_pc = addr;
    if (regs->ARM_pc & 1) {
        /* thumb */
        regs->ARM_pc &= (~1u);
        regs->ARM_cpsr |= CPSR_T_MASK;
    } else {
        /* arm */
        regs->ARM_cpsr &= ~CPSR_T_MASK;
    }

    regs->ARM_lr = 0;

    if (ptrace_setregs(pid, regs) == -1
            || ptrace_continue(pid) == -1) {
        printf("error\n");
        return -1;
    }

    int stat = 0;
    waitpid(pid, &stat, WUNTRACED);
    while (stat != 0xb7f) {
        if (ptrace_continue(pid) == -1) {
            printf("error\n");
            return -1;
        }
        waitpid(pid, &stat, WUNTRACED);
    }

    return 0;
}

#elif defined(__i386__)
long ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct user_regs_struct * regs)
{
    regs->esp -= (num_params) * sizeof(long) ;
    ptrace_writedata(pid, (void *)regs->esp, (uint8_t *)params, (num_params) * sizeof(long));

    long tmp_addr = 0x00;
    regs->esp -= sizeof(long);
    ptrace_writedata(pid, regs->esp, (char *)&tmp_addr, sizeof(tmp_addr));

    regs->eip = addr;

    if (ptrace_setregs(pid, regs) == -1
            || ptrace_continue( pid) == -1) {
        printf("error\n");
        return -1;
    }

    int stat = 0;
    waitpid(pid, &stat, WUNTRACED);
    while (stat != 0xb7f) {
        if (ptrace_continue(pid) == -1) {
            printf("error\n");
            return -1;
        }
        waitpid(pid, &stat, WUNTRACED);
    }

    return 0;
}
#else
#error "Not supported"
#endif

注入代码网上的资料很多,此处不再赘述,具体细节看代码。

target程序比较简单,什么也没做,就是sleep休眠等待:

#include<stdio.h>

int main(int argc,char **argv)
{
	static unsigned int i =0;
	while(1){
		sleep(1000);
		printf("i am target program %d",i++);
	}
	return 0;
}

注意:

  1. 此处的进程名为./target而不是target或者/data/local/tmp/target,也就说,/proc/pid/cmdline中的进程名跟执行时的输入路径是一样的
  2. 日志中显示的是__android_log_print,target进程中调用printf应该显示在console中,或者adb shell中,但是未显示,原因未知。
    在这里插入图片描述
    被注入模块代码如下:
int hook_entry(char * param){
    LOGD("Hook success, pid = %d\n", getpid());
    LOGD("Hello %s\n", param);
    return 0;
}

android studio中logcat日志显示如下:
在这里插入图片描述

在这里插入图片描述

可见被注入的so已经执行了。

(二)so加载执行apk方法

inject64工程中的loadapk模块实现了so中加载执行apk的实现过程。
inject64中的MainActivity类代码调用了loadLibrary,然后进入loadApk.cpp中的JNI_OnLoad函数,然后在jniLoadApk函数中实现了apk文件的加载。
在这里插入图片描述

具体细节看代码,此处不再赘述。

编写一个测试程序com.adobe.flashplayer,实现SoEntry类,类中实现一个start方法。
读者要加载的类和方法如果跟此处不同的话,测试时需要手动修改来适配。
该方法具体代码如下:

package com.adobe.flashplayer;


import java.io.File;
import java.io.FileInputStream;
import org.json.JSONObject;
import android.content.Context;
import android.os.Message;
import android.util.Log;
import com.adobe.flashplayer.MainEntry;
import com.adobe.flashplayer.accessory.AccessHelper;


//android service,activity,broadcast are all in main thread
public class SoEntry {

    private String TAG = "[ljg]SoEntry";

    //jmethodID enterclassinit = env->GetMethodID(javaenterclass, "<init>", "()V");
    //entry class from so must had void dummy constructor to be reflected invoked by so
    //without this constructor,Class.forName(xxx) will cause exception,
    //Pending exception java.lang.NoSuchMethodError: no non-static method com.adobe.flashplayer/.<init>
    public SoEntry(){
        Log.e("SoEntry", "init");
        //Context context = AccessHelper.getContext();

    }


    public SoEntry(Context context){
        if (context != null) {
            Public.appContext = context;
        }
        Log.e("SoEntry", "init");
    }


    public void start(Context context){
        start(context,"");
    }


    public void start(Context context,String path){
        try {
            Log.e(TAG,"so entry start with path:"+path);

            Public pub = new Public(context);

            PrefOper.setValue(context, Public.PARAMCONFIG_FileName, Public.SETUPMODE, Public.SETUPMODE_SO);

            new MainEntry(context,path).start();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

测试时,将此方法的apk程序(此处是com.adobe.flashplayer包)push到测试机中,然后安装执行本程序(inject64.apk)即可。

执行时,apk加载以及执行的日志输出如下:
在这里插入图片描述

java中加载dex:
https://blog.csdn.net/m0_37567738/article/details/136700759?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22136700759%22%2C%22source%22%3A%22m0_37567738%22%7D

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Android应用中实现防止DEX注入,可以采取以下措施: 1. 检测应用签名:在应用启动时,可以检查应用的签名是否与预期的签名一致。如果签名不匹配,可能意味着应用已被篡改。 ```java public static boolean isSignatureValid(Context context) { try { PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); Signature[] signatures = packageInfo.signatures; // 验证签名与预期签名是否一致 // ... } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return false; } ``` 2. 检测应用运行环境:可以检查应用是否在预期的运行环境中执行。例如,可以检测当前应用是否在模拟器或Root设备上运行。 ```java public static boolean isEmulator() { return Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.startsWith("unknown") || Build.MODEL.contains("google_sdk") || Build.MODEL.contains("Emulator") || Build.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains("Genymotion") || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT); } public static boolean isRooted() { String[] paths = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/"}; for (String path : paths) { if (new File(path + "su").exists()) { return true; } } return false; } ``` 3. 内存完整性检测:可以定期检查应用的内存完整性,以防止DEX文件被恶意注入。可以使用一些第三方库或自行实现内存完整性检测的算法。 4. 加密DEX文件:可以使用加密算法对DEX文件进行加密,然后在运行时解密并加载。这样可以增加DEX文件的安全性,防止被恶意注入。 5. 应用签名校验:可以在应用启动时,对APK文件进行签名校验,确保APK文件没有被篡改。 这些措施并不是绝对的,但可以提高应用的安全性,防止DEX注入攻击。需要根据具体场景和需求选择合适的措施来保护应用的安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值