问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Android逆向工程实验指南:从入门到实践

创作时间:
作者:
@小白创作中心

Android逆向工程实验指南:从入门到实践

引用
CSDN
1.
https://blog.csdn.net/qq_51585942/article/details/138768683

Android逆向工程是一种通过对已编译的Android应用进行分析,以获取其源代码、算法实现等信息的技术。这种技术在安全审计、功能分析、二次开发等领域有着广泛的应用。本文将通过四个具体的案例,详细介绍Android逆向分析的基本方法和技巧。

Android 逆向分析实验

Task 1:Case Study 1

task1.apk安装至安卓设备后,发现需要对某个输入进行校验:

随机尝试输入并进行校验,发现提示flag错误,可见需要输入正确的flag才能够通过校验。

下载dex2jar和jd-gui并为对应文件添加可执行权限。使用dex2jar将task1.apk转换为JAR文件格式:

d2j-dex2jar.sh ./task1.apk

可以看到以Java代码形式展示的task1.apk

分析可得当flag的位数与s相同(31),且每一位i均满足flag[i] ^ 0x17 == s[i](^:如果相应位值相同,则结果为0,否则为1)。按照提示写Python代码暴力破解:

s = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"  # 替换为实际的s值
flag = ""
for i in range(len(s)):
    flag += chr(ord(s[i]) ^ 0x17)
print(flag)

验证:

Task 2:Case Study 2

使用dex2jar和jd-gui读取task2.apk中的Java代码。首先检查MainActivity.class,发现其中的onClick函数检查了一个名为a的类中的一个名为a的函数的返回值,而函数a的参数为用户的输入:

public class MainActivity extends c {
    protected void onCreate(Bundle paramBundle) {
        super.onCreate(paramBundle);
        setContentView(2130968603);
        EditText editText = (EditText)findViewById(2131427422);
        findViewById(2131427423).setOnClickListener(new
View.OnClickListener(this, editText, (Context)this) {
            public void onClick(View param1View) {
                if (a.a(this.a.getText().toString())) {
                    Toast.makeText(this.b, "You get it~",1).show();
                    return;
                }
                Toast.makeText(this.b, "Sorry its wrong",1).show();
            }
        });
    }
}

检查a.class,其中的函数a如下所示:

public static boolean a(String paramString) {
    if (paramString.length() == b.length) {
        int[] arrayOfInt = new int[a.length];
        arrayOfInt[0] = 0;
        byte[] arrayOfByte = paramString.getBytes();
        int k = arrayOfByte.length;
        int i = 0;
        int j = 1;
        while (i < k) {
            arrayOfInt[j] = arrayOfByte[i];
            j++;
            i++;
        }
        i = 0;
        while (i < c.length) {
            if (a[i] == b[i] * arrayOfInt[i] * arrayOfInt[i] + c[i] *
arrayOfInt[i] + d[i] && a[i + 1] == b[i] * arrayOfInt[i + 1] * 	arrayOfInt[i+ 1] + c[i] *arrayOfInt[i + 1] + d[i]) {
i++;
                continue;
            }
            return false;
        }
        return true;
    }
    return false;
}

分析该函数。该函数中将用户输入按字节存入一个字节数组arrayOfByte,然后将arrayOfByte逐元素转存到int数组arrayOfInt中(从arrayOfInt的第二位开始,arrayOfInt的第一位为0)。arrayOfInt的长度为数组a的长度,因此可知用户输入的长度比数组a的长度少一个字节,为34个字节。最后逐元素验证数组arrayOfInt的元素是否满足16行中的数量关系,若均满足则返回true

编写Python代码破解:

b = [xxx, xxx, xxx, ...]  # 替换为实际的b数组
c = [xxx, xxx, xxx, ...]  # 替换为实际的c数组
d = [xxx, xxx, xxx, ...]  # 替换为实际的d数组
a = [xxx, xxx, xxx, ...]  # 替换为实际的a数组

flag = ""
for i in range(34):
    for j in range(256):
        if a[i] == b[i] * j * j + c[i] * j + d[i] and a[i + 1] == b[i] * (j + 1) * (j + 1) + c[i] * (j + 1) + d[i]:
            flag += chr(j)
            break
print(flag)

输入验证:

Task 3:Case Study 3

使用file命令查看task3.txt的文件类型,发现为Zip压缩文件。

使用Unzip命令解压缩后按上两个Task的方法查看Java代码。查看onClickTest函数发现函数对比了用户输入与i函数的返回值:

public void onClickTest(View paramView) {
    if (this.n.getText().toString().equals(i())) {
        this.o.setText(2131099685);
        return;
    }
    this.o.setText(2131099683);
}

i函数放在在线Java IDE中运行,并将返回值转换为String类型输出,得到flag:

Task 4:Case Study 4

同样使用dex2jar和jd-gui查看task4.apk的源代码,可以发现onCreate函数中设置了某个按钮为不可点击状态,猜测这个按钮就是查看flag的按钮。

使用AndroidKiller对task4.apk进行反编译。

查看onCreate函数的smali代码,可以找到Java代码中设置按钮状态的对应代码。其中v5寄存器在前方代码中被置为0,猜测该寄存器传递的就是参数false。将一个新寄存器v4的值置为1并替代传参语句中的v5,使传递的参数修改为true

使用AndroidKiller将修改后的文件重新编译。将生成的task4_killer.apk在安卓中运行,此时直接点击"爬到了,看Flag"按钮即可看到界面上显示出flag。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号