Android逆向系列之静态分析(三)–IDA

IDA

整体界面

共有File , Edit , Jump , Search , View , Debugger , Options , Windows , Help 9个Tab菜单

  • 1.File 文件操作相关、脚本操作相关、snapshot相关操作
  • 2.Edit 功能比较多,主要涉及修改查询注释等
  • 3.Jump 是用来跳转的,可以有很多种类型的跳转,比如跳转到上一个位置或者下一个位置,跳转到某个指定的地址。还可以根据名字,函数来进行跳转,跳转到一个新的窗口,跳转某一个偏移量等等
  • 4.Serach 搜索相关操作
  • 5.View 是用来选择显示方式的,或者显示某一特定模块信息的。比如以树形逻辑图显示,或者16进制形式显示。还可以单独显示某一特定信息,比如输入或者输出表等。
  • 6.Debugger 动态调试
  • 7.Options 在这里可以进行一下常规性的设置
  • 8.Windows 窗口相关的一些操作
  • 9.Help 使用IDA的一些帮助文档,检查更新等等。

加载文件界面

加载后界面

  • Function window:列举了IDA识别的每一个函数,双击函数可实现跳转。
  • IDA View-A:反汇编窗口,分为图形模式与文本模式,通过空格(space)可以进行切换。
  • Hex View-1:十六进制窗口,与IDA View进行配套,通过右键可以调整数据展示,F2快捷键可以修改数据(常用于动态调试 nop 命令 – 00 00 A0 E1)。
  • Structures:数据结构窗口,主要是应用自定义实现的一些数据结构体
  • Enums:枚举数窗口,显示一些枚举值
  • Imports:导入窗口,列出文件导入的函数,即调用的外部函数
  • Exports:导出窗口,列出文件的入口点,双击导出条目可实现跳转。
  • Strings:字符串窗口,Shift + F12 显示从文件中提取出来的字符串以及字符串所在地址,双击导出条目可实现跳转。右键Setup 可以修改匹配条件(Ignore instructions/data definitions 忽略指令/数据定义,勾选此项,会使IDA扫描指令和现有数据定义中的字符串)
  • Function Calls:函数调用窗口,可以看到所有调用该函数的位置和当前函数做出的全部调用
  • Output window:日志输出窗口,命令结果输出窗口,脚本结果输出窗口等
  • 其他子窗口:

ToolBar工具栏

主要涉及一些快捷操作,方便使用者进行快捷操作

可在Edit–>Toolbar中选择自定义的工具栏

Navigation Band导航条

  • 颜色条对应下面有颜色的注释,如蓝色:常规函数等
  • 最右边为可选择的匹配和标记项,可标记如入口点等等
  • Options–>colos–>Navigation Band可更改自定义的颜色

参考

《IDA Pro权威指南》

Android逆向系列之静态分析(二)–JAVA层

实例分析

2014 ASIS Cyber Security Contest Finals Numdroid

判断文件类型

首先利用 file 命令判断一下文件类型,发现是个压缩包,解压缩一下,得到对应的文件,然后继续看一下,发现该文件是 apk 文件。

安装程序

安装一下程序。简单看一下页面,可以发现程序主要是输入0-9数字密码,然后登陆。如果输入错的话会爆出 “Wrong Password” 的信息。

分析程序

1、根据相应的字符串来定位一下源程序中的关键函数。根据 strings.xml 可以发现该字符串的变量名为 wrong,继而我们找到了如下代码。

2、也可以直接切入入口函数OnCreate函数进行流程分析。

    protected void ok_clicked() {
        DebugTools.log("clicked password: " + this.mScreen.getText());
        boolean result = Verify.isOk(this, this.mScreen.getText().toString());
        DebugTools.log("password is Ok? : " + result);
        if (result) {
            Intent i = new Intent(this, LipSum.class);
            Bundle b = new Bundle();
            b.putString("flag", this.mScreen.getText().toString().substring(0, 7));
            i.putExtras(b);
            startActivity(i);
            return;
        }
        Toast.makeText(this, R.string.wrong, 1).show();
        this.mScreen.setText("");
    }

继续定位到 Verify.isOk 中。如下

    public static boolean isOk(Context c, String _password) {
        String password = _password;
        if (_password.length() > 7) {
            password = _password.substring(0, 7);
        }
        String r = OneWayFunction(password);
        DebugTools.log("digest: " + password + " => " + r);
        if (r.equals("be790d865f2cea9645b3f79c0342df7e")) {
            return true;
        }
        return false;
    }

可以发现程序主要是取 password 的前 7 位进行 OneWayFunction 加密,然后与 be790d865f2cea9645b3f79c0342df7e 进行比较。如果相等就会返回 true。这里我们再看一下 OneWayFunction,如下

    private static String OneWayFunction(String password) {
        List<byte[]> bytes = ArrayTools.map(ArrayTools.select(ArrayTools.map(new String[]{"MD2", "MD5", "SHA-1", "SHA-256", "SHA-384", "SHA-512"}, new AnonymousClass1(password)), new SelectAction<byte[]>() {
            public boolean action(byte[] element) {
                return element != null;
            }
        }), new MapAction<byte[], byte[]>() {
            public byte[] action(byte[] element) {
                int i;
                byte[] b = new byte[8];
                for (i = 0; i < b.length / 2; i++) {
                    b[i] = element[i];
                }
                for (i = 0; i < b.length / 2; i++) {
                    b[(b.length / 2) + i] = element[(element.length - i) - 2];
                }
                return b;
            }
        });
        byte[] b2 = new byte[(bytes.size() * 8)];
        for (int i = 0; i < b2.length; i++) {
            b2[i] = ((byte[]) bytes.get(i % bytes.size()))[i / bytes.size()];
        }
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(b2);
            byte[] messageDigest = digest.digest();
            StringBuilder hexString = new StringBuilder();
            for (byte aMessageDigest : messageDigest) {
                String h = Integer.toHexString(aMessageDigest & MotionEventCompat.ACTION_MASK);
                while (h.length() < 2) {
                    h = "0" + h;
                }
                hexString.append(h);
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            return "";  // 注意这里,如果算法不存在的话,应该是会返回空字符串
        }
    }

函数大概就是执行了几个hash函数,由于Hash函数是不可逆的,因此这道题的唯一解法必然是爆破,这是很明显的一道爆破题。

由于代码中没有过度混淆且逻辑比较清晰,以及Hash算法并非自定义算法,涉及到的主要流程比较少,因此我们可以直接把Verify类抠出来直接跑。

构造程序

提取出 java 程序之后,在 Verify 类中添加 main 函数并修复部分错误,从而得到对应的答案。

需要注意的点是,由于Hash算法不存在的话,会返回空字符串,因此PC端和Android可能出现相同算法出现不同的结果,原因就在这里

输入之后得到如下

然后我们计算对应的 MD 值,从而获得 flag 为 ASIS_{3c56e1ed0597056fef0006c6d1c52463}

参考

CTFWILIKI

Android逆向系列之静态分析(一)–Jeb

111111111

整体界面:

整体UI名词解释:

Action & Hotkey:

Tip:

  • Ctrl+Space 查看历史命名.
  • None input 修改为原始名称

Navigating & Hotkey

Native Code Actions

参考

JEB官网: JEB

JEB用户手册: Manual

JEB Api: Apidoc(a developer portal for advanced users who will want to use the JEB API to script tasks, develop plugins, or even craft their own front-ends)

JEB Blog: Blog
(We recommend visiting our blog for additional, pointed resources describing a variety of use cases.)

Android逆向小工具–apkCheckProtect

android小工具-查壳工具

移动端查壳并不是什么难事,主要就是特征库的维护而已。

这里V1版本仅对so文件做特征检验,其他文件检验将在下个版本体现

由于用几分钟写完,没来得及做各种兼容性适配和跨平台适配,有问题的话 可以直接评论留言

继续阅读“Android逆向小工具–apkCheckProtect”

懒人福利|一秒创建Xposed模版

*本文原创作者:Tasfa,本文属FreeBuf原创奖励计划,未经许可禁止转载

FreeBuf:http://www.freebuf.com/sectool/167274.html

懒惰是科技的第一生产力。

0×00 背景

由于Android逆向每次想要使用Xposed进行Hook时,总是需要重复性地操作一遍Android Studio新建项目的流程.ps:当然可以只用一个项目,强迫症需要分开 :)

由于Xposed实现的方式,每次修改hook代码后,需要重启机器,这也是白白浪费了很多时间。

基于以上两点,参考现有的方案,实现了一个Module,只需在AS中new一下即可解决问题。

继续阅读“懒人福利|一秒创建Xposed模版”