函数抽取脱壳工具 fart代码阅读

什么是fart

ART环境下基于主动调用的自动化脱壳方案 

fart 脱壳流程总结

1 获取当前应用的类加载器 的 (类列表)反射使函数可以调用

2 通过反射获取class的类名字

3 加载指定的类,并反射执行构造函数和成员函数

4 通过调用DexFile自定义的函数从而主动调用实现类dump

具体代码分析

先反射修改函数为可访问

获取DexFile 的mCookie 拿到class的类名

mCookie 是个啥?

直接看源码 其实就是保存的一个dex 信息

加载类和方法

加载方法又分两种方式

1 先加载类中构造函数

2 加载类中声明的函数

至于为什么 fart 能执行某个函数 我们继续往下看

Fart 在 DexFile 自定义 dumpMethodCode 函数

 

该函数是一个native 函数 参数为一个 method 对象

具体实现在 art\runtime\native\dalvik_system_DexFile.cc

伪造系统的ArtMethod Invoke 调用

在art\runtime\art_method.cc中myfartInvoke实现虚拟调用

这里传null 是有讲究的 过滤如果传进来的是我们伪造的invoke调用 直接return 不执行 但是这时候其实已经触发壳的函数解密 直接保存即可

dumpArtMethod fart 的核心函数  

dumpArtMethod 代码解释:

extern "C" void dumpArtMethod(ArtMethod * artmethod)
	 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
		char *dexfilepath = (char *) malloc(sizeof(char) * 2000); //开启dump 的空间
		if (dexfilepath == nullptr) {
			LOG(INFO) <<
			    "ArtMethod::dumpArtMethodinvoked,methodname:"
			    << PrettyMethod(artmethod).
			    c_str() << "malloc 2000 byte failed";
			return;
		}
		int fcmdline = -1;
		char szCmdline[64] = { 0 };
		char szProcName[256] = { 0 };
		int procid = getpid();
		//获取当前进程的名字
		sprintf(szCmdline, "/proc/%d/cmdline", procid);
		fcmdline = open(szCmdline, O_RDONLY, 0644);
		if (fcmdline > 0) {
			read(fcmdline, szProcName, 256);
			close(fcmdline);
		}

		if (szProcName[0]) {
			//获取dex
			const DexFile *dex_file = artmethod->GetDexFile();
			const char *methodname =
			    PrettyMethod(artmethod).c_str();、
			//dex 的起始地址
			const uint8_t *begin_ = dex_file->Begin();
			//dex 的大小
			size_t size_ = dex_file->Size();

			memset(dexfilepath, 0, 2000);
			int size_int_ = (int) size_;
            //创建dump文件夹 并加权限
			memset(dexfilepath, 0, 2000);
			sprintf(dexfilepath, "%s", "/sdcard/fart");
			mkdir(dexfilepath, 0777);

			memset(dexfilepath, 0, 2000);
			sprintf(dexfilepath, "/sdcard/fart/%s",
				szProcName);
			mkdir(dexfilepath, 0777);

			memset(dexfilepath, 0, 2000);
			//拼接dex路径
			sprintf(dexfilepath,
				"/sdcard/fart/%s/%d_dexfile.dex",
				szProcName, size_int_);
			int dexfilefp = open(dexfilepath, O_RDONLY, 0666);
			if (dexfilefp > 0) {
				close(dexfilefp);
				dexfilefp = 0;

			} else {
				dexfilefp =
				    open(dexfilepath, O_CREAT | O_RDWR,
					 0666);
				if (dexfilefp > 0) {
					write(dexfilefp, (void *) begin_,
					      size_);
					fsync(dexfilefp);
					close(dexfilefp);
				}


			}
			//获取codeitem 即被抽取的函数指令 什么是 见下图 Codeitem 
			const DexFile::CodeItem * code_item =
			    artmethod->GetCodeItem();
			if (LIKELY(code_item != nullptr)) {
				int code_item_len = 0;
				uint8_t *item = (uint8_t *) code_item;
				if (code_item->tries_size_ > 0) {
					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 {
					code_item_len =
					    16 +
					    code_item->
					    insns_size_in_code_units_ * 2;
				}
				memset(dexfilepath, 0, 2000);
				int size_int = (int) dex_file->Size();	// Length of data
				uint32_t method_idx =
				    artmethod->get_method_idx();
				sprintf(dexfilepath,
					"/sdcard/fart/%s/%d_%ld.bin",
					szProcName, size_int, gettidv1());
				int fp2 =
				    open(dexfilepath,
					 O_CREAT | O_APPEND | O_RDWR,
					 0666);
				if (fp2 > 0) {
					lseek(fp2, 0, SEEK_END);
					memset(dexfilepath, 0, 2000);
					int offset = (int) (item - begin_);
					//拼接方法的基本信息,名称、id、偏移、大小
					sprintf(dexfilepath,
						"{name:%s,method_idx:%d,offset:%d,code_item_len:%d,ins:",
						methodname, method_idx,
						offset, code_item_len);
					int contentlength = 0;
					while (dexfilepath[contentlength]
					       != 0)
						contentlength++;
					write(fp2, (void *) dexfilepath,
					      contentlength);
					long outlen = 0;
					char *base64result =
					    base64_encode((char *) item,
							  (long)
							  code_item_len,
							  &outlen);
					write(fp2, base64result, outlen);
					write(fp2, "};", 2);
					fsync(fp2);
					close(fp2);
					if (base64result != nullptr) {
						free(base64result);
						base64result = nullptr;
					}
				}

			}


		}

		if (dexfilepath != nullptr) {
			free(dexfilepath);
			dexfilepath = nullptr;
		}

	}

Codeitem

 好了 至此 fart 分析就算完毕了 总之一句话 frat 作者牛逼 !

frat 地址

GitHub - hanbinglengyue/FART: ART环境下自动化脱壳方案

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值