前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【愚公系列】2023年04月 攻防世界-MOBILE(Illusion)

【愚公系列】2023年04月 攻防世界-MOBILE(Illusion)

作者头像
愚公搬代码
发布2023-04-28 17:10:09
4510
发布2023-04-28 17:10:09
举报
文章被收录于专栏:历史专栏历史专栏

前言

下面介绍两个反编译工具

  • jadx是一个用于反编译Android APK文件的开源工具,静态反编译,查找索引功能强大
  • jeb和IDA很像,属于动态调试,可以看java汇编也可以生成伪代码,还可以动态attach到目标调试

对于so文件的逆向工具选择

  • IDA逆向工具是一款反汇编器,被广泛应用于软件逆向工程领域,能够反汇编各种不同平台的二进制程序代码,并还原成可读的汇编代码。

Objection是一款移动设备运行时漏洞利用工具,该工具由Frida驱动,可以帮助研究人员访问移动端应用程序,并在无需越狱或root操作的情况下对移动端应用程序的安全进行评估检查。

安装命令

代码语言:javascript
复制
pip3 install objection 

frida是一款便携的、自由的、支持全平台的hook框架,可以通过编写JavaScript、Python代码来和frida_server端进行交互

frida的安装可以参考:https://www.jianshu.com/p/60cfd3f6afde

一、Illusion

1.题目

在这里插入图片描述
在这里插入图片描述

2.答题

1、jadx-gui

使用jadx-gui打开apk文件

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
package monkeylord.illusion;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.InputStreamReader;

/* loaded from: classes.dex */
public class MainActivity extends Activity {
    public native String CheckFlag(String str, String str2);

    static {
        System.loadLibrary("native-lib");
    }

    @Override // android.app.Activity
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { // from class: monkeylord.illusion.MainActivity.1
            @Override // android.view.View.OnClickListener
            public void onClick(View view) {
                try {
                    String flag = ((EditText) MainActivity.this.findViewById(R.id.editText)).getText().toString();
                    String encflag = new BufferedReader(new InputStreamReader(MainActivity.this.getAssets().open("Flag"))).readLine();
                    if (encflag != null) {
                        ((TextView) MainActivity.this.findViewById(R.id.sample_text)).setText(MainActivity.this.CheckFlag(flag, encflag));
                    }
                } catch (Exception e) {
                    ((TextView) MainActivity.this.findViewById(R.id.sample_text)).setText("Something Wrong");
                }
            }
        });
    }
}

调用CheckFlag函数进行校验,这个函数传入两个参数,一个是flag,一个是encflag。其中flag是我们输入的值,encflag是存在文中进行读取的

在这里插入图片描述
在这里插入图片描述

2、ida pro进行So文件分析

搜索找到函数,进行伪代码分析

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
int __fastcall Java_monkeylord_illusion_MainActivity_CheckFlag(_JNIEnv *a1, int a2, int a3, int a4)
{
  size_t v4; // r0
  size_t i; // [sp+28h] [bp-34h]
  char *v7; // [sp+30h] [bp-2Ch]
  char *v8; // [sp+34h] [bp-28h]
  char *v9; // [sp+38h] [bp-24h]

  v9 = (char *)j_j_Jstring2CStr(a1, a3);
  v4 = j_strlen(v9);
  v8 = (char *)j_calloc(1u, v4 + 1);
  v7 = (char *)j_j_Jstring2CStr(a1, a4);
  for ( i = 0; i < j_strlen(v9); ++i )
    v8[i] = ((unsigned __int64)sub_10C0(
                                 (unsigned __int8)v9[i] + (unsigned int)(unsigned __int8)aE116c5c66e7b37[i] - 64,
                                 93) >> 32)
          + 32;
  if ( !j_strcmp(v8, v7) )
    return j__JNIEnv::NewStringUTF(a1, "Correct!");
  else
    return j__JNIEnv::NewStringUTF(a1, "Try Again!");
}

2、sub_10C0

而sub_10C0函数,则是判断a2是否等于0,然后来判断执行哪个函数 由于a2的值恒定为93,所以只执行sub_1028()函数

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
int __fastcall sub_10C0(int a1, int a2)
{
  if ( a2 )
    return sub_1028();
  else
    return sub_10AC();
}

3、sub1028

sub1028虽然有些长,但是逻辑很简单

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
int __fastcall sub_1028(unsigned int a1, unsigned int a2)
{
  int v2; // r12
  unsigned int v3; // r3
  int v4; // r2
  int result; // r0

  v2 = a1 ^ a2;
  v3 = 1;
  v4 = 0;
  if ( (a2 & 0x80000000) != 0 )
    a2 = -a2;
  if ( (a1 & 0x80000000) != 0 )
    a1 = -a1;
  if ( a1 >= a2 )
  {
    while ( a2 < 0x10000000 && a2 < a1 )
    {
      a2 *= 16;
      v3 *= 16;
    }
    while ( a2 < 0x80000000 && a2 < a1 )
    {
      a2 *= 2;
      v3 *= 2;
    }
    while ( 1 )
    {
      if ( a1 >= a2 )
      {
        a1 -= a2;
        v4 |= v3;
      }
      if ( a1 >= a2 >> 1 )
      {
        a1 -= a2 >> 1;
        v4 |= v3 >> 1;
      }
      if ( a1 >= a2 >> 2 )
      {
        a1 -= a2 >> 2;
        v4 |= v3 >> 2;
      }
      if ( a1 >= a2 >> 3 )
      {
        a1 -= a2 >> 3;
        v4 |= v3 >> 3;
      }
      if ( !a1 )
        break;
      v3 >>= 4;
      if ( !v3 )
        break;
      a2 >>= 4;
    }
  }
  result = v4;
  if ( v2 < 0 )
    return -v4;
  return result;
}

将用户输入的每个字符,加上内置data字符串对应的下标的字符,然后再减去64; 得到的结果,取余93后,进行比较

3.脚本

代码语言:javascript
复制
enc_flag = "Ku@'G_V9v(yGS"
data = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"
data = [ord(i) for i in data]


def main():
    enc = [ord(i) for i in enc_flag]
    flag = [0]*len(enc)
    for i in range(len(enc)):
        flag[i] = (enc[i]-32)+64-data[i]
        while flag[i] < 0x32:
            flag[i] += 93
        while flag[i] > 125:
            flag[i] -= 93
    print("".join([chr(i) for i in flag]))


if __name__ == '__main__':
    main()
# CISCN{GJ5728}

或者暴力解析

代码语言:javascript
复制
package com.test;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.arm.HookStatus;
import com.github.unidbg.hook.HookContext;
import com.github.unidbg.hook.ReplaceCallback;
import com.github.unidbg.hook.hookzz.HookZz;
import com.github.unidbg.linux.android.AndroidARMEmulator;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.pointer.UnidbgPointer;
import com.sun.jna.Pointer;
import unicorn.Arm64Const;
import unicorn.ArmConst;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class illusion extends AbstractJni {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;
    private DvmClass cNative;
    private static String r0;

    private illusion () {
        // 创建模拟器实例,进程名建议依照实际进程名填写,可以规避针对进程名的校验
        emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("monkeylord.illusion").build();
        // 获取模拟器的内存操作接口
        final Memory memory = emulator.getMemory();
        // 设置系统类库解析
        memory.setLibraryResolver(new AndroidResolver(23));
        // 创建Android虚拟机,传入APK,Unidbg可以替我们做部分签名校验的工作
//        vm =  emulator.createDalvikVM(new File("unidbg-android/src/test/java/com/test/llusion.apk"));
        vm =  emulator.createDalvikVM();
        // 加载目标SO
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/java/com/test/libnative-lib.so"), true); // 加载so到虚拟内存
        //获取本SO模块的句柄,后续需要用它
        module = dm.getModule();
        vm.setJni(this); // 设置JNI
        vm.setVerbose(false); // 打印日志

        dm.callJNI_OnLoad(emulator); // 调用JNI OnLoad
    }

    public static void main(String[] args) {
        illusion test = new illusion();
        test.hook();
        String flag_enc = "Ku@'G_V9v(yGS";

        String flag = "";

        for (int index = 0; index < flag_enc.length(); index++) {
            for (int i = 33; i < 127; i++) {
                test.CheckFlag(flag + String.valueOf((char) i), flag_enc);  // 进行判断
                if ((illusion.r0.length() > index)  && (flag_enc.charAt(index) == illusion.r0.charAt(index))) {
                    flag += String.valueOf((char) i);
                    break;
                }
            }
            System.out.println("Flag[0:"+index+"]: "+flag);
        }

        System.out.println("Completely Flag is: "+flag);

    }

    private void CheckFlag(String flag, String flag_enc) {
        //创建jobject对象
        DvmObject<?> thiz = vm.resolveClass("monkeylord.illusion").newObject(null);
        List<Object> list = new ArrayList<>(10);
        list.add(vm.getJNIEnv());
        list.add(0);  
        list.add(vm.addLocalObject(new StringObject(vm, flag)));   // arg 3
        list.add(vm.addLocalObject(new StringObject(vm, flag_enc)));   // arg 4

        Number number =  module.callFunction(emulator, 0xdc9, list.toArray());
//        System.out.print("result:");
//        DvmObject<?> object = vm.getObject(number.intValue());
//        System.out.print(object.getValue().toString());
    }

    public void hook() {
        HookZz hook = HookZz.getInstance(emulator);
        hook.replace(module.base + 0x00000E64+1, new ReplaceCallback() {
            @Override
            public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
//                System.out.println(context.getPointerArg(0).getString(0));  // 入参1 R0寄存器
                illusion.r0 = context.getPointerArg(0).getString(0);
//                System.out.println(context.getPointerArg(1).getString(0));  // 入参2 R1寄存器
                return super.onCall(emulator, context,originFunction);
            }

        }, true);
    }
}

得到flag为:CISCN{GJ5728}

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-04-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、Illusion
    • 1.题目
      • 2.答题
        • 3.脚本
        相关产品与服务
        腾讯云代码分析
        腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档