[TOC]
了解了编译、打包、签名、安装apk文件后,正式开始逆向的基础,静态分析
apk包内的dex文件是dalvik虚拟机可识别的可执行文件,我们主要也是对dex文件进行逆向,分析其代码逻辑、更改其逻辑做一些分析、破解之类的行为
这里我们用一个去广告的例子,简单的过一下流程
java -jar apktool.jar d xxx.apk -o out
注入+栈追踪
,我们可以先用字符串大法先随意拼接以下ad字符串大致定位一下,可能会在哪个文件夹中,挑选出下面包含类所在文件夹批量注入日志打印方法
python3 inject_log.py -r .\out\smali\com\youdo
const/4 v0, 0x0
,让返回始终为null
const/4 v0, 0x0 return-object v0首先针对不同逆向,我们需要清楚逆向的目的,在crakeme赛题中,我们主要目的是找到flag,具体需要我们找到打印输出的地方,在其周围找到判断逻辑,然后就是最主要的一部分逆向算法,算出flag
1.反编译
2.定位关键代码
3.逆向算法
反编译后,查看AndroidManifest.xml找到入口 点
<activity android:label="@h/a" android:name="ctf.bobbydylan.M">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
进入这个Activity类中,我们根据执行逻辑,如果有static{}和构造方法,我们可以看一眼里面除了初始化是否还有别的东西,这里并没有这两个调用,我们直接去onCreate方法中,这个Acitivity创建时调用的方法
分析代码:主要有个开启服务的方法,进入这个P服务类,扫一眼生命周期中用到的方法,并没有值得留意的东西,直接看onStartCommand方法,服务启动时执行的方法,这里是循环播放res/raw目录下的音频文件bodylan,这个类分析到这,不是什么重要的类,接着往下看
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.main);
startService(new Intent(this, P.class));
((Button) findViewById(R.id.button)).setOnClickListener(new a(this, (TextView) findViewById(R.id.et)));
}
public int onStartCommand(Intent intent, int i, int i2) {
try {
if (this.a == null) {
this.a = MediaPlayer.create(this, R.raw.bobdylan);
this.a.start();
this.a.setLooping(true);
}
} catch (Exception e) {
}
return super.onStartCommand(intent, i, i2);
}
按钮控件设置监听方法,在Jadx-Gui中右键->Find Usage找到方法定义的地方,可以从中文字符看出我们找到了主要逻辑,我们的目的就是打印出正确二字,从这个逻辑中可以看出,我们必须保证this.b.check
不能抛出异常才行,下面才是crakeme真正开始的地方,分析这个check方法
a(M m, TextView textView) {
this.b = m;
this.a = textView;
}
public void onClick(View view) {
try {
this.b.check(this.a.getText().toString());
new Builder(this.b).setMessage("正确").setNeutralButton("OK", null).create().show();
} catch (Exception e) {
new Builder(this.b).setMessage("错误").setNeutralButton("OK", null).create().show();
}
}
我们必须保证不抛出异常
满足下面注释的两个条件即可
public void check(String str) {
int i = 0;
//条件1:输入字符串长度必须等于16
if (str.length() != 16) {
throw new RuntimeException();
}
String str2 = "";
try {
str2 = getKey();
} catch (Exception e) {
str2 = getKey();
System.arraycopy(str2, 0, str, 5, 5);
}
int[] iArr = new int[16];
iArr[0] = 0;
iArr[12] = 14;
iArr[10] = 7;
iArr[14] = 15;
iArr[15] = 42;
try {
iArr[1] = 3;
iArr[5] = 5;
System.out.println();
} catch (Exception e2) {
iArr[5] = 37;
iArr[1] = 85;
}
iArr[6] = 15;
iArr[2] = 13;
iArr[3] = 19;
iArr[11] = 68;
iArr[4] = 85;
iArr[13] = 5;
iArr[9] = 7;
iArr[7] = 78;
iArr[8] = 22;
//条件2:iArr数组&255必须和后面这串计算相等
while (i < str.length()) {
if ((iArr[i] & 255) != ((str.charAt(i) ^ str2.charAt(i % str2.length())) & 255)) {
throw new RuntimeException();
}
i++;
}
}
public String getKey() {
return "bobbydylan";
}
根据面的分析写出第一版算不出结果的解密脚本,然后我用androidkiller打开这个apk文件,看汇编代码发现这个getKey不是调用M类中的方法,因为是个乱码,实际上是调用了父类中继承的方法
iArr = [0, 3, 13, 19, 85, 5, 15, 78, 22, 7, 7, 68, 14, 5, 15, 42]
chArr = ['b', 'o', 'b', 'b', 'y', 'd', 'y', 'l', 'a', 'n']
for i in iArr:
number = 0
while(True):
if iArr[i] == number ^ ord(chArr[i%len('bobbydylan')]):
print(chr(number))
if i == len(iArr):
print("end")
exit(0)
break
number += 1
解密算法,结果blow,in the winD
iArr = [0, 3, 13, 19, 85, 5, 15, 78, 22, 7, 7, 68, 14, 5, 15, 42]
chArr = ['b', 'o', 'b', 'd', 'y', 'l', 'a', 'n']
for i in range(len(iArr)):
number = 0
while(True):
if iArr[i] == number ^ ord(chArr[i%len('bobdylan')]):
print(chr(number))
if i == len(iArr):
print("end")
exit(0)
break
number += 1
【1】当java层代码不能给我们正确答案是,可以阅读smali代码
根据这几篇文章的逆向流程来分析病毒即可
【1】zoopark https://www.freebuf.com/articles/system/184286.html
【2】锁屏病毒 https://www.freebuf.com/articles/others-articles/199515.html
上面从具体逆向的一些分支的实现中来了解一下java层的具体实现,难度其实没那么大,但是需要对Android开发一些基础知识有一定的掌握
【1】批量注入栈跟踪小工具
【2】crakeme赛题 https://bbs.pediy.com/thread-251787-1.htm
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。