其他
Android题目分析部分思路总结
本文为看雪论坛优秀文章
看雪论坛作者ID:以和爲貴
1.Strange apk:firda dump正在运行的dex文件
2.app3:怎么打开.ab文件,jeb动态调试
3.ph0en1x_100:jeb动态调试
4.easydex:so层静态分析,idc脚本
一
Strange apk
先看manifest文件,找到程序的入口点:
protected void onCreate(Bundle arg5) {
super.onCreate(arg5);
this.setContentView(0x7F09001D);
View input_str = this.findViewById(0x7F070022);
// 输入字符串
this.findViewById(0x7F07008A);
((Button)input_str).setOnClickListener(new View$OnClickListener(this.findViewById(0x7F070037)) {
public void onClick(View arg9) {
String str1 = "";
// 两个字符串临时存储变量
String str2 = "";
int t = 0;
// 临时变量
String str = this.val$ed.getText().toString();
int num_30 = 30;
if(str.length() == num_30) {
// 输入的字符串的长度为30
while(t < 12) {
str1 = str1 + str.charAt(t);
// 将前12个输入的字符存储到str1里面
++t;
}
str1 = f.sctf(str1);
// 跟进去发现是将前12个字符进行base64加密
while(t < num_30) {
str2 = str2 + str.charAt(t);
// 将后12个字符存储到str2字符串里面
++t;
}
if(str1.equals("c2N0ZntXM2xjMG1l")) {
// 根据字符串1和该字符串相匹配,直接就能解出来前12个字符sctf{W3lc0me
Intent v4_1 = new Intent();
v4_1.putExtra("data_return", str2);
//返回.t文件中分析str2字符串的加密操作
s.this.setResult(-1, v4_1);
s.this.finish();
}
else {
Toast.makeText(s.this.getApplicationContext(), "something wrong", 1).show();
}
}
else {
Toast.makeText(s.this.getApplicationContext(), "something wrong", 1).show();
}
}
});
}
}
public class t extends AppCompatActivity {
public t() {
super();
}
protected void onActivityResult(int arg9, int arg10, Intent arg11) {
View v0 = this.findViewById(0x7F07008B);
View v1 = this.findViewById(0x7F070023);
if(arg9 == 1 && arg10 == -1) {
try {
MessageDigest str = MessageDigest.getInstance("MD5");
str.update("syclover".getBytes());
// 将syclover字符串进行md5加密
String temp_str = new BigInteger(1, str.digest()).toString(16);
// 将加密后的字符转化为字符串8bfc8af07bca146c937f283b8ec768d4
}
catch(Exception v5) {
v5.printStackTrace();
}
if(f.encode(arg11.getStringExtra("data_return"), temp_str).equals("~8t808_8A8n848r808i8d8-8w808r8l8d8}8")) {
((TextView)v0).setVisibility(0);
((Button)v1).setVisibility(4);
// 去除所有的8之后剩下~t0_An4r0id-w0rld}
}
else {
Toast.makeText(this.getApplicationContext(), "one more step", 1).show();
}
}
}
public static String encode(String temp_str, String str) { // 将data_return字符串和加密后的字符串8bfc8af07bca146c937f283b8ec768d4格一位放一个
int len_temp_str = temp_str.length();
int len_str = str.length();
StringBuilder t_str = new StringBuilder();
int t;
for(t = 0; t < len_temp_str; ++t) {
t_str.append(temp_str.charAt(t));
t_str.append(str.charAt(t / len_str)); // 每次都是只能取到第一个字符8
}
return t_str.toString(); // 返回字符8
}
这道题的关键所在就是,找到程序的入口点,dump出正在运行的dex文件,字符串加密简单分析即可得到。
二
app3
一般的话.ab文件是用这个文件进行操作的
我总结出来一般的话使用这两条指令中的一条:
java -jar abe-all.jar unpack app3.ab app3.jar
java -jar abe-all.jar unpack app3.ab app3.tar
将.ab文件转化为.tar文件
解压缩之后发现了apk文件,就可以进行分析了:
先从程序的入口点开始分析:
private void a() {
SQLiteDatabase.loadLibs(((Context)this));
// 加载数据库
this.b = new a(((Context)this), "Demo.db", null, 1);
ContentValues v0 = new ContentValues();
// 实例化v0这个对象,用于存储用户名和密码
v0.put("name", "Stranger");
// name = Stranger
v0.put("password", Integer.valueOf(0x1E240));
// password = 0x1E240 = 123456
com.example.yaphetshan.tencentwelcome.a.a v1 = new com.example.yaphetshan.tencentwelcome.a.a();
// 初始化v1对象
String v2 = v1.a(v0.getAsString("name"), v0.getAsString("password"));
// 将获取到的用户名和密码的值转化为字符型变量存储到v2中,调用的v1.a方法,然后跟进去分信息v1.a的方法,如果传入两个参数,就是分别取0-4个字符,就是返回Stra1234
this.a = this.b.getWritableDatabase(v1.a(v2 + v1.b(v2, v0.getAsString("password"))).substring(0, 7));
// 调用了数据库函数,将刚刚的变量作为参数传入,调用了v1.a的方法和v1.b的方法
this.a.insert("TencentMicrMsg", null, v0);
}
String v2 = v1.a(v0.getAsString("name"), v0.getAsString("password"));
最后这个代码这里,由于这里是给数据库传参数的函数,所以就是要分析这个,一开始的那个tar文件里面解压之后发现了.db文件,就是数据库文件,所以我猜测,这里传入的参数应该是登录数据库的密码,重点就是要分析这个函数了。
this.a = this.b.getWritableDatabase(v1.a(v2 + v1.b(v2, v0.getAsString("password"))).substring(0, 7));
v1.b(v2, v0.getAsString("password"))
package com.example.yaphetshan.tencentwelcome.a;
public class a {
private String a;
public a() {
super();
this.a = "yaphetshan";
}
public String a(String arg4, String arg5) {
return arg4.substring(0, 4) + arg5.substring(0, 4); // 返回值截取0-4位字符
}
public String a(String arg3) {
new b();
return b.b(arg3 + this.a); // 调用了b方法,跟进去分析一下
}
public String b(String arg2, String arg3) {
new b();
return b.a(arg2);
}
}
其实也没有什么,就是md5加密和SHA-1加密。
先获得这个函数的返回值:
跟进去下个断点:
接下来就要看看这个函数的返回值了
v1.a(v2 + v1.b(v2, v0.getAsString("password")))
继续下断点:
然后分析这个:
(v1.a(v2 + v1.b(v2, v0.getAsString("password"))).substring(0, 7))
下断点,再调:
v0 = "ae56f99638285eb0743d8bf76d2b0c80e5cbb096"
然后取前七位:ae56f99(这就是登录数据库的密码了,其实直接从最后一步那里下断点就行了,我想一步步的看看加密算法的结果)
这一眼就是base64编码,直接解码就行了
Tctf{H3ll0_Do_Y0u_Lov3_Tenc3nt!}
三
ph0en1x_100
关键代码就是这里,修复一下代码在分析就是这样的:
protected void onCreate(Bundle arg2) {
super.onCreate(arg2);
this.setContentView(0x7F040019);
this.input_flag = this.findViewById(0x7F0C004F);
}
public void onGoClick(View arg5) {
if(this.getSecret(this.getFlag()).equals(this.getSecret(this.encrypt(this.input_flag.getText().toString())))) {
Toast.makeText(((Context)this), "Success", 1).show();
}
else {
Toast.makeText(((Context)this), "Failed", 1).show();
}
}
if(this.getSecret(this.getFlag()).equals(this.getSecret(this.encrypt(this.input_flag.getText().toString()))))
先看一下getflag()函数:
再看一下encrypt()函数:
下好断点,附加进程:
直接上脚本就行了:
四
easydex
发现只有一些资源文件,并没有发现dex文件,所以dex文件应该也是动态加载出来的。
这里我尝试用frida-dexdump想dump下正在运行的dex文件,但是啥也没有:
所以就要分析so层了:
一看这么多逻辑,先动态看看程序是怎么走的吧:
先在这里下个断点,可以找出程序在系统中(经过了异或运算)的释放的dex文件的位置。
这个是我修复之后的代码:
这里有两种方法:
1.在删除dex文件操作之前下个断点,然后将手机中的dex文件pull到电脑上
2.使用idc脚本直接解密出dex文件:
看雪ID:以和爲貴
https://bbs.pediy.com/user-home-939330.htm
# 往期推荐
2.Frida inlineHook原理分析及简单设计一款AArch64 inlineHook工具
球分享
球点赞
球在看
点击“阅读原文”,了解更多!