吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 50562|回复: 135
收起左侧

[Android 脱壳] APK加固之静态脱壳机编写入门

    [复制链接]
我是小三 发表于 2015-10-30 21:08
        本教程只适合菜鸟学习,大牛请过......{:1_930:}{:1_928:}
目录
0.jpg


0x00 APK加固简介与静态脱壳机的编写思路
1.大家都知道Android中的程序反编译比较简单,辛苦开发出一个APK轻易被人反编译了,所以现在就有很多APK加固的第三方平台,比如爱加密和梆梆加固等。
2.一般的加固保护通常能够提供如下保护:加密、防逆向、防篡改、反调试、反窃取等功能,编写静态脱壳机须要信息有加密后的原始DEX数据、解密算法、解密密钥、要想获得这些信息我们首先要解决的问题是过反调试、动态分析解密流程、获取密钥,获得原始DEX数据存放位置、分析解密算法。
0x01 壳简单分析

1.整体来看一下加固前APK包和加固后的APK包结构相关变化,如图1所示。

1

1
   图1
图1所示加固后的APK增加了librsprotect.so、librsprotect_x86.so、rsprotect.dat文件,发生变化的有AndroidManifest.xml、classes.dex文件。
2.反编译加固后APK,APK中的AndroidManifest.xml文件的入口被修改,如图2所示。

2

2
   图2
3.入口类中主要会调用librsprotect.so中的3个函数,如图3所示。
private native void initialize(ContextparamContext);
private native ApplicationmakeApplication(String paramString);

private native void applicationOnCreate();

3

3
   图3
0x02SO文件静态脱壳
1.既然主要是调用librsprotect.so中的函数,我们将librsprotect.so放到IDA Pro中分析,发现代码都是乱码 图4所示,说明被加密了。

4

4
   图4
2.一般加壳的SO的壳代码都在INIT段或INIT_ARRAY段,我们先看下被加壳以后的SO信息,用readelf -a命令查看,图5所示

5

5
   图5
可以看到INIT值为0x2ea91,到 IDA中看看该地址的内容,就是壳的入口了,明显是UPX的加壳,图6所示,有人会问你为什么会知道是UPX的壳,“只是因为在人群中多看了你一眼,再也没能忘掉你容颜!(^_^)”。

6

6
   图6
3.尝试用upx -d脱壳,因为这样脱方便、干净、省事、提示图7所示的错误信息。

7

7
   图7
查看UPX源码后发现可能是没有找到UPX!的标志的原因,用16进制工具打开librsprotect.so发现标志被改成了RSP!,将其改成UPX!后再将尝试,出现 图8所示的信息。

8

8
   图8
出现这种错误可能是做变形处理了或者是版本不对,通过分析librsprotect.so的壳代码好像没有变形处理,所以决定重新编一个3.92版本的来试试,编译好后脱壳成功,如图9所示。

9

9
   图9
将脱壳后的so放到IDA Pro中分析,代码正常,图10所示,SO脱壳完成。

10

10
   图10
0x03反调试分析
1.如何使用IDA调试android的SO模块,网上教程也太多太多了,这里不多说,将脱壳后的librsprotect.so替换掉原始有壳的SO后(也可不用替换没影响,这里只是为了测试)签名安装进行动态分析。

2.通过动态调试该加壳程序,它用到的反调试方法是首先试探性读取/proc/pid/status获取进程状态去判断是否有调试器,如果发现被调试就kill掉本进程,如图11所示

11

11
   图11
3.通过读取/proc/net/tcp查看正在运行应用的本地端口号是否有android_server端口,如果有就创建一个反调试线程,如图12、13所示,每隔几秒检查一次,过反调试就很简单了直接把返回值改成假就成了。

12

12
   12 android_server运行后端口

13

13
   图13
0x04 解密流程分析

1.      根据算法中的常量值猜测该算法为MD5,图14所示

14

14
   图14
2.获取包名并计算MD5值 图15所示,将该值做为密钥。
com.droider.crackme0201
F2 E8 F0 62 85 17 9C 3C 99 F5 67 9F A6 27 FC 55

15

15
   图15
2.打开并读取/data/data/com.droider.crackme0201/files/.rsdata/rsprotect.dat数据,该文件是从APK包中的assets文件夹中拷贝过来的,判断前4字节是"RSFL"是否与so中的相同,不同则退出,rsprotect.dat前0x1000字节存放原始DEX大小与循环解密的次数,每次解密0x1000字节,根据密钥初始化流程发现解密算法为RC4,图16示。

16

16
   图16
0x05 脱壳机编写
1.通过分析,已经知道了壳的数据、密钥、算法、解密过程, 现在来写脱壳机。
必要步骤如下:
1。解包获得rsprotect.da数据。
2.XML解析获得包名。
3.MD5计算获得密钥。
4.RC4解密rsprotect.dat中的数据。

代码流程:
[C++] 纯文本查看 复制代码
#include"stdafx.h"
#include<afxwin.h>
#include<stdio.h>
#include<windows.h>
#include<process.h>
#include<assert.h>
#include<string>
#include<iostream>
#include"CMarkup.h"
#include"md5.h"
#include"rc4.h"
#include<string>
usingnamespacestd;
BOOLGetPackName(char* pathXml, charoutPackName[256])
{
	CMarkupxml;
	boolflag;
	CStringpackName;
	CStringAppandroidname;
	MCD_STRmyapkName;
	MCD_STRattribName;
	char* strXML = "\\AndroidManifest.xml";
	strcat(pathXml,strXML);
	flag = xml.Load((MCD_STR)pathXml);
	if ( FALSE == flag)
	{
		printf("获得包名失败...\n");
		returnFALSE;
	}
	flag = xml.FindElem((MCD_STR)"manifest");
	//获取包名.........
	for(intattribIndex=0;;attribIndex++)
	{
		attribName=xml.GetAttribName(attribIndex);
		if (attribName.GetLength()!=0)  //方法若返回empty string,即表示属性结束,结束循环
		{
			MCD_STRattribVal = xml.GetAttrib(attribName);//否则读取属性值,以子元素加入dxml
			//------判断是否为包名...
			packName = attribName.GetString();
			if ( 0 == strcmp(packName.GetString(), "package"))
			{
				myapkName = attribVal;
				strcpy(outPackName, attribVal.GetString());
				returnTRUE;
			}
		}
		else
			break;
	} 
	returnFALSE;
}
voidStrToHex(BYTE *pbDest, BYTE *pbSrc, intnLen)
{
	charh1,h2;
	BYTEs1,s2;
	inti;
	for (i=0; i<nLen; i++)
	{
		h1 = pbSrc[2*i];
		h2 = pbSrc[2*i+1];
		s1 = toupper(h1) - 0x30;
		if (s1> 9) 
			s1 -= 7;
		s2 = toupper(h2) - 0x30;
		if (s2> 9) 
			s2 -= 7;
		pbDest[i] = s1*16 + s2;
	}
}
int_tmain(intargc, _TCHAR* argv[])
{
charstrAPK[512] = {0};
	charapkd[256] = "";
	charFileDirectory[512] = {0};
	chardexDirectory[512] = {0};
	charPackName[256] = {0};
	BOOLret = FALSE;
	structrc4_staterc4_test;
	FILE *fp;
	DWORDfileSize = 0;
	BYTE *ptr = NULL;
	DWORDDecOffset = 0X1000;//文件偏移
	DWORDDecSize = 0X0;//大小
	DWORDindex = 0;//循环解密的次数
	stringkey;
	printf("请输入要脱壳的apk包路径:\n");
	scanf("%s",strAPK);
	if (NULL == strAPK)
	{
		printf("路径不能为空!\n");
		return -1;
	}
	strcpy(apkd, "java -jar apktool.jar d ");
	strcat(apkd, strAPK);
	//--------bat解包
	CFileapktool("apktool.bat", CFile::modeCreate | CFile::modeReadWrite);
	apktool.Write(apkd, strlen(apkd));
	apktool.Write("\r\n", strlen("\r\n"));
	apktool.Close();
	char* cmd1 = "apktool.bat";
	STARTUPINFOsi1;
	GetStartupInfo(&si1);
	si1.dwFlags = STARTF_USESHOWWINDOW;
	si1.wShowWindow = SW_HIDE;
	PROCESS_INFORMATIONpi1;
	CreateProcess(NULL, 
		(LPSTR)cmd1, 
		NULL, 
		NULL, 
		FALSE, 
		CREATE_NEW_CONSOLE,
		NULL, 
		NULL, 
		&si1, 
		&pi1);
	printf("正在解包apk...\n");
	WaitForSingleObject(pi1.hProcess,INFINITE);
	DeleteFile("apktool.bat");
	printf("解包完成...\n");
	//-----判断是否解包成功..........
	strncpy(FileDirectory, strAPK, strlen(strAPK)-strlen(".apk"));
	DWORDdwFileAtt;
	dwFileAtt = GetFileAttributes(FileDirectory);
	//判断是否为目录
	if( dwFileAtt != FILE_ATTRIBUTE_DIRECTORY)
	{
		printf("apk解包失败!...\n");
		return 0;
	}
	printf("apk解包成功!...\n");
	strcpy(dexDirectory, FileDirectory);
	//得到包名
	ret = GetPackName(FileDirectory,PackName);
	if (FALSE == ret)
	{
		printf("获得包名失败...\n");
		return -1;
	}
	//计算MD5值
	MD5md5(PackName);
	key = md5.md5();
	strcat(dexDirectory, "\\assets\\rsprotect.dat");
	fp=fopen(dexDirectory, "rb");
	if(fp==NULL)
		printf("打开文件失败!...");
	//求文件大小
	fseek(fp, 0, SEEK_END);  
	fileSize = ftell(fp); 
	fseek(fp, 0, SEEK_SET);
	ptr = (BYTE*)malloc(fileSize);
	if (NULL == ptr)
	{
		puts("malloc error");
	}
	memset(ptr,fileSize,0);
	fread(ptr, sizeof(BYTE), fileSize, fp);
	fclose(fp);
	//--解密dex
	DecSize = *(DWORD*)(ptr+12);
	index = *(DWORD*)(ptr+0x10);
	ptr += DecOffset;
	if (0 == DecSize)
	{
		printf("要解密的dex大小出错\n");
		return -1;
	}
	memset(&rc4_test,0,sizeof(rc4_test));
	unsignedcharDecKey[32] = {0};
	for (inti=0; i<32; i++)
	{
		DecKey[i] = key[i];
	}
	unsignedcharkey1[32] ={0};
	StrToHex(key1, DecKey, 0x10);
	//--生成解密后的dex文件
	fp = fopen("classes.dex","wb");
	if (NULL == fp)
	{
		printf("File open error\n");
	}
	for (inti=0; i<index; i++)
	{
		//初始化Key
		init_Key(&rc4_test, key1, 0x10);
		//解密数据
		rc4_crypt(&rc4_test, ptr, DecOffset);

		fwrite(ptr, sizeof(BYTE), DecOffset, fp);
		ptr+=DecOffset;
	}
	fclose(fp);
	if (NULL != ptr)
	{
		free(Temp);
		ptr = NULL;
		Temp = NULL;
	}

	printf("解密完成!^_^\n");
	return 0;
}
0x06测试与总结

1.运行UnPack.exe输入要解密的APK包路径,成功解密后重新打包并正常反编译,如图17、18所示。

17

17
   图17

18

18
   图18
2.以上就是简单实现一般APK加固静态脱壳机的编写步骤,由于该加固核心so文件使用UPX默认加壳并未做变形处理,导致so被轻松的静态脱卓,而so模块中的反调试手段比较初级且模块化,可以非常简单的手工patch函数一处反回值就可完全过掉,总的来说无论是静态脱壳还是动态dump都是很容易的。

完。
样本 src pdf IDB 下载
src_样本_IDB_pdf.part01.rar (2 MB, 下载次数: 382)
src_样本_IDB_pdf.part03.rar (2 MB, 下载次数: 342)
src_样本_IDB_pdf.part04.rar (2 MB, 下载次数: 320)
src_样本_IDB_pdf.part05.rar (2 MB, 下载次数: 319)
src_样本_IDB_pdf.part06.rar (1.22 MB, 下载次数: 326)
src_样本_IDB_pdf.part02.rar (2 MB, 下载次数: 416)

点评

谢谢分享 支持楼主  发表于 2015-11-4 10:26
小三也有情,小三也有爱,小三的世界没有人关怀  发表于 2015-11-2 09:46
小三也有情,小三也有爱,小三的世界没有人关怀  发表于 2015-10-31 20:58

免费评分

参与人数 42吾爱币 +1 热心值 +42 收起 理由
814047 + 1 + 1 楼主,这方法360加固还可以用?
小小金 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
miracles + 1 谢谢@Thanks!
supperlitt + 1 用心讨论,共获提升!
卷卷de小白 + 1 用心讨论,共获提升!
Amanda小黑 + 1 用心讨论,共获提升!
mqlv + 1 用心讨论,共获提升!
jikefeng + 1 谢谢@Thanks!
k18556 + 1 小三也有情,小三也有爱,小三的世界没有人.
退役单身 + 1 谢谢@&amp;lt;span id=&amp;quot;transmark&amp;quot;&amp;gt;
星空无限 + 1 热心回复!
张小_懒 + 1 谢谢@Thanks!
netle8 + 1 谢谢@Thanks!
daydream + 1 我很赞同!
杭行天下 + 1 谢谢@Thanks!
强煎鸡蛋的鸡 + 1 我很赞同!
woainidongchao + 1 我很赞同!
hohoqzzn + 1 我很赞同!
yyshun + 1 鼓励转贴优秀软件安全工具和文档!
RCKLV + 1 牛逼呀,占个坑
kangkai + 1 小三也有情,小三也有爱。
sherlock + 1 谢谢@Thanks!
Tortoise + 1 谢谢@Thanks!
ljrlove2008 + 1 我很赞同!
bxtww + 1 我很赞同!
Hmily + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
听鬼哥说故事 + 1 热心回复!
yzh2004 + 1 谢谢@Thanks!
无痕软件 + 1 长贱识了。
XhyEax + 1 我很赞同!
楚轩 + 1 我来关怀你了
钱蛋儿 + 1 谢谢@Thanks!
woainiheibao + 1 我很赞同!
yuluo5566 + 1 我很赞同!
Sound + 1 谢谢@Thanks!
qtfreet00 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
Some + 1 感谢分享精彩教程
Terrorblade + 1 我很赞同!
huangn2008 + 1 谢谢@Thanks!
kingsunto + 1 我很赞同!
zengchuan + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
bigharvest + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

liuganchao 发表于 2015-11-11 09:28

首先支持楼主发帖,讲得很细致。
其次,楼主能否把
代码流程:
[C++] 纯文本查看 复制代码
一下的代码行弄成
将脱壳后的so放到IDA Pro中分析,代码正常,图10所示,SO脱壳完成。
这样的图片格式,善于保存。
最后,楼主能否把下载资源设置成网盘形式,一是节约论坛上传资源,二是方便共享。。
再次感谢楼主发帖共享,期望再发精华帖子。。
头像被屏蔽
yaojing 发表于 2015-10-30 21:28
xiawan 发表于 2015-10-30 21:28
mycc 发表于 2015-10-30 23:36
是要接触一下移动安全了
gy3026 发表于 2015-10-30 23:55
前排留名,好厉害
hua5551 发表于 2015-10-31 00:59
还有挺多牛人分享的。。
【=筱筱=】 发表于 2015-10-31 09:46
然而我什么都看不懂

免费评分

参与人数 1热心值 +1 收起 理由
【=不依不饶=】 + 1 感谢您的宝贵建议,我们会努力争取做得更好.

查看全部评分

雁字回时月man楼 发表于 2015-10-31 12:55 来自手机
技术牛人,必须支持
a5680497 发表于 2015-10-31 13:03
完全看不懂啊
soulovess 发表于 2015-10-31 20:53
首先支持楼主发帖,讲得很细致。
其次,楼主能否把
代码流程:
[C++] 纯文本查看 复制代码
一下的代码行弄成
将脱壳后的so放到IDA Pro中分析,代码正常,图10所示,SO脱壳完成。
这样的图片格式,善于保存。
最后,楼主能否把下载资源设置成网盘形式,一是节约论坛上传资源,二是方便共享。。
再次感谢楼主发帖共享,期望再发精华帖子。。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-3-29 15:46

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表