热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ava代码注入java代码注入_动态注入并执行Android代码到进程

layout:posttitle:动态注入并执行Android代码到进程categories:Androiddescription:动态注入并执行Android代码到进程keywo

layout: post

title: 动态注入并执行Android代码到进程

categories: Android

description: 动态注入并执行Android代码到进程

keywords: Inject

url: https://lichao890427.github.io/ https://github.com/lichao890427/

动态注入并执行Android代码到进程

背景

网上可以见到很多帖子是如何注入进程并钩取c层api的例子,而动态的让目标进程加载一个dex并执行这个dex却没看到,c层的注入很简单,可以参考adbi,ptrace进去修改当前指令指针寄存器,构造一个dlopen的指令并调用,类似于win上getcontext修改eip, java层稍复杂一些,加载dex->解析dex->查找目标类->调用函数,下面是测试用例,我们的目标是打log

代码

import android.util.Log;

public class injectjava {

static void initialize(){

Log.i("INJECTJAVA","injectava called");

}

}

#define LOGI(...) __android_log_print(ANDROID_LOG_ERROR, "INJECTJAVA", __VA_ARGS__)

#define DEXNAME "/data/local/tmp/inject.dex"

typedef void Object;

typedef void ClassObject;

typedef void Thread;

typedef uint8_t u1;

typedef uint32_t u4;

struct JNIEnvExt

{

const struct JNINativeInterface* funcTable;

const struct JNINativeInterface* baseFuncTable;

u4 envThreadId;

Thread* self;

};

typedef void DexOptHeader;

typedef void DexStringId;

typedef void DexTypeId;

typedef void DexFieldId;

typedef void DexMethodId;

typedef void DexProtoId;

typedef void DexLink;

typedef void DexClassLookup;

struct DexHeader

{

u1 magic[8]; /* includes version number */

u4 checksum; /* adler32 checksum */

u1 signature[20]; /* SHA-1 hash */

u4 fileSize; /* length of entire file */

u4 headerSize; /* offset to start of next section */

u4 endianTag;

u4 linkSize;

u4 linkOff;

u4 mapOff;

u4 stringIdsSize;

u4 stringIdsOff;

u4 typeIdsSize;

u4 typeIdsOff;

u4 protoIdsSize;

u4 protoIdsOff;

u4 fieldIdsSize;

u4 fieldIdsOff;

u4 methodIdsSize;

u4 methodIdsOff;

u4 classDefsSize;

u4 classDefsOff;

u4 dataSize;

u4 dataOff;

};

struct DexClassDef

{

u4 classIdx; /* index into typeIds for this class */

u4 accessFlags;

u4 superclassIdx; /* index into typeIds for superclass */

u4 interfacesOff; /* file offset to DexTypeList */

u4 sourceFileIdx; /* index into stringIds for source file name */

u4 annotationsOff; /* file offset to annotations_directory_item */

u4 classDataOff; /* file offset to class_data_item */

u4 staticValuesOff; /* file offset to DexEncodedArray */

};

struct DexFile

{

DexOptHeader *pOptHeader;

DexHeader *pHeader;

DexStringId *pStringIds;

DexTypeId *pTypeIds;

DexFieldId *pFieldIds;

DexMethodId *pMethodIds;

DexProtoId *pProtoIds;

DexClassDef *pClassDefs;

DexLink *pLinkData;

DexClassLookup *pClassLookup;

};

struct DvmDex

{

DexFile* pDexFile;

};

int (*dvmDexFileOpenPartial)(const void* addr, int len, DvmDex** ppDvmDex)=0;

int (*dexSwapAndVerify)(void* addr, int len)=0;

JNIEnv* (*dvmGetJNIEnvForThread)()=0;

Object* (*dvmDecodeIndirectRef)(JNIEnv* env, jobject jobj)=0;

Object* (*dvmDecodeIndirectRef_)(Thread* self, jobject jobj)=0;

ClassObject* (*dvmDefineClass)(DvmDex* pDvmDex, const char* descriptor, Object* classLoader)=0;

DexClassLookup* (*dexCreateClassLookup)(DexFile* pDexFile)=0;

void inject()

{

/*

* C层hook

*/

/*

* JAVA层hook

*/

//获取关键函数指针

do

{

void* hdvm = dlopen("libdvm.so", RTLD_LAZY | RTLD_GLOBAL);

if(!hdvm)

{

LOGI("libdvm not exist!");

break;

}

dvmDexFileOpenPartial = (typeof(dvmDexFileOpenPartial))dlsym(hdvm, "dvmDexFileOpenPartial");

if(!dvmDexFileOpenPartial)

{

dvmDexFileOpenPartial = (typeof(dvmDexFileOpenPartial))dlsym(hdvm, "_Z21dvmDexFileOpenPartialPKviPP6DvmDex");

if(!dvmDexFileOpenPartial)

LOGI("dvmDexFileOpenPartial not exist!");

}

dexSwapAndVerify = (typeof(dexSwapAndVerify))dlsym(hdvm, "dexSwapAndVerify");

if(!dexSwapAndVerify)

{

dexSwapAndVerify = (typeof(dexSwapAndVerify))dlsym(hdvm, "_Z16dexSwapAndVerifyPhi");

if(!dexSwapAndVerify)

LOGI("dexSwapAndVerify not exist!");

}

dvmGetJNIEnvForThread = (typeof(dvmGetJNIEnvForThread))dlsym(hdvm, "dvmGetJNIEnvForThread");

if(!dvmGetJNIEnvForThread)

{

dvmGetJNIEnvForThread = (typeof(dvmGetJNIEnvForThread))dlsym(hdvm, "_Z21dvmGetJNIEnvForThreadv");

if(!dvmGetJNIEnvForThread)

LOGI("dvmGetJNIEnvForThread not exist!");

}

dvmDecodeIndirectRef = (typeof(dvmDecodeIndirectRef))dlsym(hdvm, "dvmDecodeIndirectRef");

if(!dvmDecodeIndirectRef)

{

dvmDecodeIndirectRef = (typeof(dvmDecodeIndirectRef))dlsym(hdvm, "_Z20dvmDecodeIndirectRefP7_JNIEnvP8_jobject");

if(!dvmDecodeIndirectRef)

{

dvmDecodeIndirectRef_ = (typeof(dvmDecodeIndirectRef_))dlsym(hdvm, "_Z20dvmDecodeIndirectRefP6ThreadP8_jobject");

if(!dvmDecodeIndirectRef_)

LOGI("dvmDecodeIndirectRef_ not exist!");

}

}

dvmDefineClass = (typeof(dvmDefineClass))dlsym(hdvm, "dvmDefineClass");

if(!dvmDefineClass)

{

dvmDefineClass = (typeof(dvmDefineClass))dlsym(hdvm, "_Z14dvmDefineClassP6DvmDexPKcP6Object");

if(!dvmDefineClass)

LOGI("dvmDefineClass not exist!");

}

dexCreateClassLookup = (typeof(dexCreateClassLookup))dlsym(hdvm, "dexCreateClassLookup");

if(!dexCreateClassLookup)

{

dexCreateClassLookup = (typeof(dexCreateClassLookup))dlsym(hdvm, "_Z20dexCreateClassLookupP7DexFile");

if(!dexCreateClassLookup)

LOGI("dexCreateClassLookup not exist!");

}

if(!dvmDexFileOpenPartial || !dexSwapAndVerify || !dvmGetJNIEnvForThread || !dvmDefineClass || !dexCreateClassLookup || (!dvmDecodeIndirectRef && !dvmDecodeIndirectRef_))

break;

LOGI("InitOk");

//读取dex以便动态加载

char* dexdata = 0;

int dexlen;

int dexfd = open(DEXNAME, O_RDONLY);

if(dexfd == -1)

{

LOGI("can't open inject.dex!");

break;

}

struct stat st = {0};

fstat(dexfd , &st);

if(st.st_size)

{

dexlen = st.st_size;

dexdata = (char*)malloc(st.st_size);

if(dexdata)

read(dexfd, dexdata, st.st_size);

}

close(dexfd);

if(!dexdata)

{

LOGI("read inject.dex fail!");

break;

}

int result;

DvmDex* dvmDex = 0;

JNIEnv* env =0;

jclass java_lang_Class =0;

jmethodID java_lang_Class_forName =0;

jclass java_lang_ClassLoader =0;

jmethodID java_lang_ClassLoader_getSystemClassLoader =0;

jobject jSystemClassLoader =0;

Object* SystemClassLoader =0;

jstring com_injectjava_str =0;

jclass com_injectjava =0;

jmethodID com_injectjava_initialize =0;

DexFile* pDexFile = 0;

int csize,i;

dexSwapAndVerify(dexdata, dexlen);

result = dvmDexFileOpenPartial(dexdata, dexlen, &dvmDex);

if(result != 0)

{

LOGI("dvmDexFileOpenPartial fail!");

goto END1;

}

env = dvmGetJNIEnvForThread();

if(!env)

{

LOGI("dvmGetJNIEnvForThread fail!");

goto END1;

}

java_lang_Class = env->FindClass("java/lang/Class");

if(!java_lang_Class)

{

LOGI("java_lang_Class null!");

goto END1;

}

java_lang_Class_forName = env->GetStaticMethodID(java_lang_Class, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");

if(!java_lang_Class_forName)

{

LOGI("java_lang_Class_forName null!");

goto END1;

}

java_lang_ClassLoader = env->FindClass("java/lang/ClassLoader");

if(!java_lang_ClassLoader)

{

LOGI("java_lang_ClassLoader null!");

goto END1;

}

java_lang_ClassLoader_getSystemClassLoader = env->GetStaticMethodID(java_lang_ClassLoader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");

if(!java_lang_ClassLoader_getSystemClassLoader)

{

LOGI("java_lang_ClassLoader_getSystemClassLoader null!");

goto END1;

}

jSystemClassLoader = env->CallStaticObjectMethod(java_lang_ClassLoader, java_lang_ClassLoader_getSystemClassLoader, "()Ljava/lang/ClassLoader;");

if(!jSystemClassLoader)

{

LOGI("jSystemClassLoader null!");

goto END1;

}

LOGI("InitOk1");

if(dvmDecodeIndirectRef)

SystemClassLoader = dvmDecodeIndirectRef(env, jSystemClassLoader);

else

SystemClassLoader = dvmDecodeIndirectRef_(((JNIEnvExt*)env)->self, jSystemClassLoader);

if(!SystemClassLoader)

{

LOGI("SystemClassLoader null!");

goto END1;

}

pDexFile = dvmDex->pDexFile;

pDexFile->pClassLookup = dexCreateClassLookup(dvmDex->pDexFile);

csize = pDexFile->pHeader->classDefsSize;

for(i=0;i

{

pDexFile->pClassDefs[i].accessFlags | 0x10000;

}

dvmDefineClass(dvmDex, "Lcom/injectjava;", SystemClassLoader);

com_injectjava_str = env->NewStringUTF("com.injectjava");

if(!com_injectjava_str)

{

LOGI("com_injectjava null!");

goto END1;

}

com_injectjava = (jclass)env->CallStaticObjectMethod(java_lang_Class, java_lang_Class_forName, com_injectjava_str, true, jSystemClassLoader);

if(!com_injectjava)

{

LOGI("com_injectjava null!");

goto END1;

}

com_injectjava_initialize = env->GetStaticMethodID(com_injectjava, "initialize", "()V");

if(!com_injectjava_initialize)

{

LOGI("com_injectjava_initialize null!");

goto END1;

}

env->CallStaticVoidMethod(com_injectjava, com_injectjava_initialize);

LOGI("InitOk2");

END1:

free(dexdata);

}

while(false);

}

结论

将要执行的dex放到/data/local/tmp/inject.dex即可

06-03 15:47:34.984 16197-16197/com.example.hellojni E/INJECTJAVA: InitOk

06-03 15:47:35.074 16197-16197/com.example.hellojni E/INJECTJAVA: InitOk1

06-03 15:54:08.304 16197-16197/com.example.hellojni I/INJECTJAVA: injectava called

这里只是做实验验证Java代码的注入原理分析,Frida注入框架是这类动态注入的最佳实践框架



推荐阅读
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
author-avatar
小米和南瓜
这个家伙很懒,什么也没留下!
RankList | 热门文章