本文为看雪论优秀文章
看雪论坛作者ID:misskings
public static void main(String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new ActivityThread.EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
private static ActivityThread sCurrentActivityThread;
public static ActivityThread currentActivityThread() {
return sCurrentActivityThread;
}
private void attach(boolean system) {
sCurrentActivityThread = this;
}
public static void loop() {
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
} else {
MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
long ident = Binder.clearCallingIdentity();
while(true) {
Message msg = queue.next();
if (msg == null) {
return;
}
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf("Looper", "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (this.mCallback != null && this.mCallback.handleMessage(msg)) {
return;
}
this.handleMessage(msg);
}
}
final ActivityThread.H mH = new ActivityThread.H();
final Handler getHandler() {
return this.mH;
}
case 110:
Trace.traceBegin(64L, "bindApplication");
ActivityThread.AppBindData data = (ActivityThread.AppBindData)msg.obj;
ActivityThread.this.handleBindApplication(data);
Trace.traceEnd(64L);
break;
然后继续看handleBindApplication,我们就可以看到大神所说的重要的点了:
Application app = data.info.makeApplication(data.restrictedBackupMode, (Instrumentation)null);
this.mInitialApplication = app;
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
this.installContentProviders(app, providers);
this.mH.sendEmptyMessageDelayed(132, 10000L);
}
}
try {
this.mInstrumentation.onCreate(data.instrumentationArgs);
} catch (Exception var20) {
throw new RuntimeException("Exception thrown in onCreate() of " + data.instrumentationName + ": " + var20.toString(), var20);
}
try {
this.mInstrumentation.callApplicationOnCreate(app);
} catch (Exception var26) {
if (!this.mInstrumentation.onException(app, var26)) {
throw new RuntimeException("Unable to create application " + app.getClass().getName() + ": " + var26.toString(), var26);
}
}
ContextImpl appContext = ContextImpl.createAppContext(this.mActivityThread, this);
app = this.mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);
public static Application newApplication(Class<?> clazz, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
final void attach(Context context) {
this.attachBaseContext(context);
this.mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
FART脱壳的步骤主要分为三步:
1. 内存中DexFile结构体完整dex的dump
2. 主动调用类中的每一个方法,并实现对应CodeItem的dump
3. 通过主动调用dump下来的方法的CodeItem进行dex中被抽取的方法的修复
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
fartthread();
}
public static void fartthread() {
new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
try {
Log.e("ActivityThread", "start sleep......");
Thread.sleep(1 * 60 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e("ActivityThread", "sleep over and start fart");
fart();
Log.e("ActivityThread", "fart run over");
}
}).start();
}
public static void fart() {
ClassLoader appClassloader = getClassloader();
ClassLoader tmpClassloader=appClassloader;
ClassLoader parentClassloader=appClassloader.getParent();
//如果当前classloader不是根,就脱他
if(appClassloader.toString().indexOf("java.lang.BootClassLoader")==-1)
{
fartwithClassloader(appClassloader);
}
//如果有父节点,并且父节点不是根,就脱他。一直脱到根节点就结束
while(parentClassloader!=null){
if(parentClassloader.toString().indexOf("java.lang.BootClassLoader")==-1)
{
fartwithClassloader(parentClassloader);
}
tmpClassloader=parentClassloader;
parentClassloader=parentClassloader.getParent();
}
}
public static ClassLoader getClassloader() {
ClassLoader resultClassloader = null;
//这里反射获取到的currentActivityThread
Object currentActivityThread = invokeStaticMethod(
"android.app.ActivityThread", "currentActivityThread",
new Class[]{}, new Object[]{});
//这里反射获取出mBoundApplication
Object mBoundApplication = getFieldOjbect(
"android.app.ActivityThread", currentActivityThread,
"mBoundApplication");
Application mInitialApplication = (Application) getFieldOjbect("android.app.ActivityThread",
currentActivityThread, "mInitialApplication");
Object loadedApkInfo = getFieldOjbect(
"android.app.ActivityThread$AppBindData",
mBoundApplication, "info");
//反射获取出目标application
Application mApplication = (Application) getFieldOjbect("android.app.LoadedApk", loadedApkInfo, "mApplication");
//获取classloader
resultClassloader = mApplication.getClassLoader();
return resultClassloader;
}
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
if (this.mApplication != null) {
return this.mApplication;
} else {
Application app = null;
//...省略中间app创建的若干代码
this.mActivityThread.mAllApplications.add(app);
this.mApplication = app;
//...省略中间若干代码
return app;
}
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//....
//省略中间的代码
//add
fartthread();
//add
return activity;
}
ClassLoader cl = ClassLoader.getSystemClassLoader();
cl.loadClass("com.example.demo");
这里可以看到直接通过loadClass取到的classLoader,那么这个函数是怎么做到的呢,下面贴下代码追踪ClassLoader.java中的loadClass
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
return c;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
private final DexPathList pathList;
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException(
"Didn't find class "" + name + "" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
public Class findClass(String name, List<Throwable> suppressed) {
DexPathList.Element[] arr$ = this.dexElements;
int len$ = arr$.length;
for(int i$ = 0; i$ < len$; ++i$) {
DexPathList.Element element = arr$[i$];
DexFile dex = element.dexFile;
if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, this.definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
}
if (this.dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(this.dexElementsSuppressedExceptions));
}
return null;
}
然后继续看返回值的来源是通过loadClassBinaryName来获取的。继续看看实现的代码:
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
return defineClass(name, loader, this.mCookie, suppressed);
}
private static Class defineClass(String name, ClassLoader loader, long cookie, List<Throwable> suppressed) {
Class result = null;
try {
result = defineClassNative(name, loader, cookie);
} catch (NoClassDefFoundError var7) {
if (suppressed != null) {
suppressed.add(var7);
}
} catch (ClassNotFoundException var8) {
if (suppressed != null) {
suppressed.add(var8);
}
}
return result;
}
public static void fartwithClassloader(ClassLoader appClassloader) {
List<Object> dexFilesArray = new ArrayList<Object>();
//这个是刚刚的findClass的pathList。这里通过反射获取。不过这个下面没使用。
Field pathList_Field = (Field) getClassField(appClassloader, "dalvik.system.BaseDexClassLoader", "pathList");
//和上面一样。不过这个是直接获取这个属性的结果出来,比上面多了个field.get()
Object pathList_object = getFieldOjbect("dalvik.system.BaseDexClassLoader", appClassloader, "pathList");
//通过反射获取dexElements,这个流程可以直接回顾上面的findClass。基本是一样的。
Object[] ElementsArray = (Object[]) getFieldOjbect("dalvik.system.DexPathList", pathList_object, "dexElements");
Field dexFile_fileField = null;
try {
dexFile_fileField = (Field) getClassField(appClassloader, "dalvik.system.DexPathList$Element", "dexFile");
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
Class DexFileClazz = null;
try {
//反射获取dexfile类型
DexFileClazz = appClassloader.loadClass("dalvik.system.DexFile");
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
Method getClassNameList_method = null;
Method defineClass_method = null;
Method dumpDexFile_method = null;
Method dumpMethodCode_method = null;
//通过反射将4个函数的值填充上
for (Method field : DexFileClazz.getDeclaredMethods()) {
//这个应该是用来获取类名称列表的
if (field.getName().equals("getClassNameList")) {
getClassNameList_method = field;
getClassNameList_method.setAccessible(true);
}
//这个是我们在上面loadClass流程最后看到的函数
if (field.getName().equals("defineClassNative")) {
defineClass_method = field;
defineClass_method.setAccessible(true);
}
//这个用来保存整个dex的,是fart里面的代码
if (field.getName().equals("dumpDexFile")) {
dumpDexFile_method = field;
dumpDexFile_method.setAccessible(true);
}
//这个应该是用来保存函数代码的,也是fart里面的代码
if (field.getName().equals("dumpMethodCode")) {
dumpMethodCode_method = field;
dumpMethodCode_method.setAccessible(true);
}
}
//这个是获取mCookie字段。不过后面也是没有用到的
Field mCookiefield = getClassField(appClassloader, "dalvik.system.DexFile", "mCookie");
Log.v("ActivityThread->methods", "dalvik.system.DexPathList.ElementsArray.length:" + ElementsArray.length);//5个
//下面是遍历所有dexfile,然后主动调用所有函数
for (int j = 0; j < ElementsArray.length; j++) {
Object element = ElementsArray[j];
Object dexfile = null;
try {
//先是反射取出每个dexfile
dexfile = (Object) dexFile_fileField.get(element);
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
if (dexfile == null) {
Log.e("ActivityThread", "dexfile is null");
continue;
}
if (dexfile != null) {
//然后取出dexfile中的mcookie,这里为什么从mInternalCookie可以在android源码中看到mCookie本身就是由mInternalCookie赋值的
dexFilesArray.add(dexfile);
Object mcookie = getClassFieldObject(appClassloader, "dalvik.system.DexFile", dexfile, "mCookie");
if (mcookie == null) {
Object mInternalCookie = getClassFieldObject(appClassloader, "dalvik.system.DexFile", dexfile, "mInternalCookie");
if(mInternalCookie!=null)
{
mcookie=mInternalCookie;
}else{
Log.v("ActivityThread->err", "get mInternalCookie is null");
continue;
}
}
//再根据mcookie获取dexfile的所有类名
String[] classnames = null;
try {
classnames = (String[]) getClassNameList_method.invoke(dexfile, mcookie);
} catch (Exception e) {
e.printStackTrace();
continue;
} catch (Error e) {
e.printStackTrace();
continue;
}
//最后遍历所有类,调用每个类中的所有函数
if (classnames != null) {
for (String eachclassname : classnames) {
loadClassAndInvoke(appClassloader, eachclassname, dumpMethodCode_method);
}
}
}
}
return;
}
继续看看fart怎么做到的调用每个类中的所有函数。
public static void loadClassAndInvoke(ClassLoader appClassloader, String eachclassname, Method dumpMethodCode_method) {
Class resultclass = null;
Log.i("ActivityThread", "go into loadClassAndInvoke->" + "classname:" + eachclassname);
try {
//由于我们反射取到了类名,所以这里直接用我们前面看到的loadClass就可以取到对应的classloader了
resultclass = appClassloader.loadClass(eachclassname);
} catch (Exception e) {
e.printStackTrace();
return;
} catch (Error e) {
e.printStackTrace();
return;
}
//反射遍历所有构造函数,并且调用前面准备好了传过来的保存构造函数代码的方法,直接调用就可以dump每个构造函数的代码了
if (resultclass != null) {
try {
Constructor<?> cons[] = resultclass.getDeclaredConstructors();
for (Constructor<?> constructor : cons) {
if (dumpMethodCode_method != null) {
try {
dumpMethodCode_method.invoke(null, constructor);
} catch (Exception e) {
e.printStackTrace();
continue;
} catch (Error e) {
e.printStackTrace();
continue;
}
} else {
Log.e("ActivityThread", "dumpMethodCode_method is null ");
}
}
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
//这里反射获取所有的函数,然后用前面准备的dump方法把所有函数都dump下来
try {
Method[] methods = resultclass.getDeclaredMethods();
if (methods != null) {
for (Method m : methods) {
if (dumpMethodCode_method != null) {
try {
dumpMethodCode_method.invoke(null, m);
} catch (Exception e) {
e.printStackTrace();
continue;
} catch (Error e) {
e.printStackTrace();
continue;
}
} else {
Log.e("ActivityThread", "dumpMethodCode_method is null ");
}
}
}
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
}
}
private static native void dumpMethodCode(Object m);
static void DexFile_dumpMethodCode(JNIEnv* env, jclass,jobject method) {
if(method!=nullptr)
{
ArtMethod* proxy_method = jobject2ArtMethod(env, method);
myfartInvoke(proxy_method);
}
return;
}
extern "C" void myfartInvoke(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) {
JValue *result=nullptr;
Thread *self=nullptr;
uint32_t temp=6;
uint32_t* args=&temp;
uint32_t args_size=6;
artmethod->Invoke(self, args, args_size, result, "fart");
}
void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
const char* shorty) {
if (self== nullptr) {
dumpArtMethod(this);
return;
}
}
extern "C" void dumpArtMethod(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) {
char *dexfilepath=(char*)malloc(sizeof(char)*1000);
if(dexfilepath==nullptr)
{
LOG(ERROR) << "ArtMethod::dumpArtMethodinvoked,methodname:"<<artmethod->PrettyMethod().c_str()<<"malloc 1000 byte failed";
return;
}
int result=0;
int fcmdline =-1;
char szCmdline[64]= {0};
char szProcName[256] = {0};
int procid = getpid();
//我查了下,/proc/pid/cmdline 是可以读取到进程的启动参数。启动参数的默认第一个一般都是进程的完整路径
sprintf(szCmdline,"/proc/%d/cmdline", procid);
fcmdline = open(szCmdline, O_RDONLY,0644);
if(fcmdline >0)
{
result=read(fcmdline, szProcName,256);
if(result<0)
{
LOG(ERROR) << "ArtMethod::dumpdexfilebyArtMethod,open cmdline file file error";
}
close(fcmdline);
}
if(szProcName[0])
{
const DexFile* dex_file = artmethod->GetDexFile();
//要保存dexfile的起始位置
const uint8_t* begin_=dex_file->Begin(); // Start of data.
//要保存dexfile的大小
size_t size_=dex_file->Size(); // Length of data.
memset(dexfilepath,0,1000);
int size_int_=(int)size_;
//先初始化目录/sdcard/fart 创建目录并给0777的权限
memset(dexfilepath,0,1000);
sprintf(dexfilepath,"%s","/sdcard/fart");
mkdir(dexfilepath,0777);
//然后把cmdline中读取到的路径在fart中同样创建目录,这样就可以区分不同的apk的结果写在不同目录
memset(dexfilepath,0,1000);
sprintf(dexfilepath,"/sdcard/fart/%s",szProcName);
mkdir(dexfilepath,0777);
//最后创建要写入保存的文件
memset(dexfilepath,0,1000);
sprintf(dexfilepath,"/sdcard/fart/%s/%d_dexfile.dex",szProcName,size_int_);
int dexfilefp=open(dexfilepath,O_RDONLY,0666);
//这里相当于是查一下这个文件是否存在。如果fp大于0表示存在,则不用再dump了。
if(dexfilefp>0){
close(dexfilefp);
dexfilefp=0;
}else{
int fp=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666);
if(fp>0)
{
//将要保存的数据写入文件,这种应该是属于整体dump
result=write(fp,(void*)begin_,size_);
if(result<0)
{
LOG(ERROR) << "ArtMethod::dumpdexfilebyArtMethod,open dexfilepath file error";
}
fsync(fp);
close(fp);
//下面是把所有类名写入文件保存。方便搜索。可能修复的时候也会用到这个文件
memset(dexfilepath,0,1000);
sprintf(dexfilepath,"/sdcard/fart/%s/%d_classlist.txt",szProcName,size_int_);
int classlistfile=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666);
if(classlistfile>0)
{
//这里我瞅着眼熟,然后翻了下。其实就是参考GetClassNames的处理。获取了所有的类名列表,然后写入文件
for (size_t ii= 0; ii< dex_file->NumClassDefs(); ++ii)
{
const DexFile::ClassDef& class_def = dex_file->GetClassDef(ii);
const char* descriptor = dex_file->GetClassDescriptor(class_def);
result=write(classlistfile,(void*)descriptor,strlen(descriptor));
if(result<0)
{
LOG(ERROR) << "ArtMethod::dumpdexfilebyArtMethod,write classlistfile file error";
}
const char* temp="n";
result=write(classlistfile,(void*)temp,1);
if(result<0)
{
LOG(ERROR) << "ArtMethod::dumpdexfilebyArtMethod,write classlistfile file error";
}
}
fsync(classlistfile);
close(classlistfile);
}
}
}
//下面是要对函数进行dump
const DexFile::CodeItem* code_item = artmethod->GetCodeItem();
if (LIKELY(code_item != nullptr))
{
int code_item_len = 0;
uint8_t *item=(uint8_t *) code_item;
//这里表示是否有try,因为try的数量会影响函数的大小,我们dump需要函数的位置和计算出函数大小。
if (code_item->tries_size_>0) {
//有try的情况计算比较复杂,这个codeitem_end里面封装了一系列的计算,我感觉好像是获取了try的数量,然后再一系列的计算,最终得到的函数大小
const uint8_t *handler_data = (const uint8_t *)(DexFile::GetTryItems(*code_item, code_item->tries_size_));
uint8_t * tail = codeitem_end(&handler_data);
code_item_len = (int)(tail - item);
}else{
//如果没有try的情况。就简单的可以计算出来。
code_item_len = 16+code_item->insns_size_in_code_units_*2;
}
//有了函数的大小和位置后,这里又获取了函数的index
memset(dexfilepath,0,1000);
int size_int=(int)dex_file->Size();
uint32_t method_idx=artmethod->GetDexMethodIndexUnchecked();
//最后把获取到的相关数据按照特定的格式写入.bin的文件中。这个文件后面就可以拿来做修复dex。因为已经有了对每个函数的详细描述了。
sprintf(dexfilepath,"/sdcard/fart/%s/%d_ins_%d.bin",szProcName,size_int,(int)gettidv1());
int fp2=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666);
if(fp2>0){
lseek(fp2,0,SEEK_END);
memset(dexfilepath,0,1000);
int offset=(int)(item - begin_);
sprintf(dexfilepath,"{name:%s,method_idx:%d,offset:%d,code_item_len:%d,ins:",artmethod->PrettyMethod().c_str(),method_idx,offset,code_item_len);
int contentlength=0;
while(dexfilepath[contentlength]!=0) contentlength++;
result=write(fp2,(void*)dexfilepath,contentlength);
if(result<0)
{
LOG(ERROR) << "ArtMethod::dumpdexfilebyArtMethod,write ins file error";
}
long outlen=0;
char* base64result=base64_encode((char*)item,(long)code_item_len,&outlen);
result=write(fp2,base64result,outlen);
if(result<0)
{
LOG(ERROR) << "ArtMethod::dumpdexfilebyArtMethod,write ins file error";
}
result=write(fp2,"};",2);
if(result<0)
{
LOG(ERROR) << "ArtMethod::dumpdexfilebyArtMethod,write ins file error";
}
fsync(fp2);
close(fp2);
if(base64result!=nullptr){
free(base64result);
base64result=nullptr;
}
}
}
}
if(dexfilepath!=nullptr)
{
free(dexfilepath);
dexfilepath=nullptr;
}
}
uint8_t* codeitem_end(const uint8_t **pData)
{
uint32_t num_of_list = DecodeUnsignedLeb128(pData);
for (;num_of_list>0;num_of_list--) {
int32_t num_of_handlers=DecodeSignedLeb128(pData);
int num=num_of_handlers;
if (num_of_handlers<=0) {
num=-num_of_handlers;
}
for (; num > 0; num--) {
DecodeUnsignedLeb128(pData);
DecodeUnsignedLeb128(pData);
}
if (num_of_handlers<=0) {
DecodeUnsignedLeb128(pData);
}
}
return (uint8_t*)(*pData);
}
//反射获取指定类的指定字段
public static Field getClassField(ClassLoader classloader, String class_name,
String filedName) {
try {
Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
return field;
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
//反射获取指定对象的指定字段的值
public static Object getClassFieldObject(ClassLoader classloader, String class_name, Object obj,
String filedName) {
try {
Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
Object result = null;
result = field.get(obj);
return result;
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
//反射获取指定对象的指定字段的值。这里注意和上面一个函数的区别是,上面使用了loadClass获取类,这里使用forName获取的,两者获取的class对象是不同的
public static Object getFieldOjbect(String class_name, Object obj,
String filedName) {
try {
Class obj_class = Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
return field.get(obj);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
return null;
}
//反射调用指定类的指定函数,并返回结果
public static Object invokeStaticMethod(String class_name,
String method_name, Class[] pareTyple, Object[] pareVaules) {
try {
Class obj_class = Class.forName(class_name);
Method method = obj_class.getMethod(method_name, pareTyple);
return method.invoke(null, pareVaules);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
最后贴一下简单的流程图。
如果写的有啥问题。希望大佬们能指正。
看雪ID:misskings
https://bbs.pediy.com/user-home-659397.htm
*本文由看雪论坛 misskings 原创,转载请注明来自看雪社区。
安卓应用层抓包通杀脚本发布!
《高研班》2021年3月班开始招生!👇
* 戳图片了解详情
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!
本文始发于微信公众号(看雪学院):fart的理解和分析过程
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论