攻防世界 黑客精神unidbg破解

6 篇文章 0 订阅
3 篇文章 1 订阅

攻防世界 黑客精神unidbg破解

一、Jadx分析

首先用jadx打开apk文件,查看MainActivity可以发现,页面判断了MyApp.m这个类变量的值,并调用类work()这个函数,且当类变量m的值为0时会跳转到RegActivity注册页面
请添加图片描述RegActivity界面比较简单,就是把输入的sn传入MyApp.saveSN()函数,然后退出,可以看出关键都在MyApp这个类。
请添加图片描述所以我们继续查看MyApp这个类,发现类有三个native函数,所以需要进一步分析so文件。
请添加图片描述### 二、IDA PRO分析

(1)找关键函数

将对应的so文件拖到ida pro后通过Export栏可以发现有JNi_OnLoad函数,说明函数为动态注册,所以进入JNi_OnLoad函数查看注册的函数。
请添加图片描述Tips: ida pro直接反编译的格式可能会很乱,这个时候可以把变量右键设置set item type设置成为JNIEnv*,然后许多函数都能解析出来类,就好看了很多(如果不知道设置哪一个变量,就把能试试的都试一便,总有一个能行_

通过分析Onload函数可以发现注册函数在off_5044这个位置上,点击跳转后发现注册的函数名字符串找到了,但是函数名却是n1,n2,n3,可以对这些函数重命名,这样好看一点儿。
请添加图片描述由此三个关键函数,work(), initSN(), saveSN()就找到了。

(2)分析关键函数
- work()函数分析

进入work函数,将传入的变量类型右键设置set lvar type设置为JNIEnv*后,F5反编译如下,可以看到该函数用getValue的方法获取了MyApp.m的值(getValue 函数用同样的方法进行反编译),然后将unk_2EFB或unk_2F25处的值赋给了V3,其中unk_2F25处的值啥也看不到,unk_2EFB处的值能看到有flag字样,应该和flag有关。最后该函数调用类callWork函数(反编译了一下,暂时没看懂,不过不重要)
请添加图片描述因此work函数的主要逻辑就是判断MyApp.m的值是否为1,如果为1则赋值对应地址的值给V3,然后调用callWork。

- initSN()函数分析

进入initSN()函数分析其逻辑为:读取reg.dat的内容,如果内容为"EoPAoY62@ElRD",则MyApp.m的值设置为1,否则为0
请添加图片描述

- saveSN()函数分析

进入saveSN()函数分析,首先修改变量类型,使得反编译更加人性化,一般变量第一个为JEIEnv*, 第二个参数jobject或者jclass, 后面的参数就是传入的native 函数中传入的参数,依次修改尝试就行。
请添加图片描述通过分析代码,v10为数组的索引,从0-sn的长度,依次增长,然后将v10的值会在字符串的指定位置取一个值来与sn对应索引位置的字符串作异或运算。所以可以看出逻辑应该为,输入的sn的每一位和字符串"W3_arE_whO_we_ARE"的固定位置的字符进行了异或运算,然后输出到V8上,最后使用f_puts函数保存到文件中。(至于在"W3_arE_whO_we_ARE"取了那几位,不重要,反正异或运算可逆)

(3)整体流程思路

通过分析三个函数,可以看出该程序的整体调用思路为,work->initSN->saveSN,逻辑思路为:

  • (1) work函数:判断MyApp.m的值是否为1,然后赋值对应地址的值给v3
  • (2) initSN函数:判断reg.dat的内容是否为 “EoPAoY62@ElRD”,若是则MyApp.m赋值为1
  • (3) saveSN函数: 将输入的sn与"W3_arE_whO_we_ARE"做异或运算后保存到reg.dat中

通过jadx可以看出只有当MyApp.m的值为1时才算已注册,所以reg.dat的内容应该为"EoPAoY62@ElRD",而reg.dat的内容是根据输入sn与字符串"W3_arE_whO_we_ARE"通过异或的算法得出的,因此只要将"EoPAoY62@ElRD"与字符串"W3_arE_whO_we_ARE"做异或运算的算法,也能得出我们应该输入的sn,及输入"EoPAoY62@ElRD"进行注册就能得到应该输入的sn。

三、unidbg脚本编写

通过编写unidbg脚本,需要实现的函数有

  • saveSN: 主动调用saveSN函数,传入sn参数
  • f_puts: saveSN函数中的子函数,hook该函数可以得到运算后的字符串
  • work: 打印work中的地址unk_2EFB查看是否有提示

整体代码如下

package com.hack;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
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.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.memory.Memory;
import com.sun.jna.JNIEnv;
import com.sun.jna.Pointer;
import unicorn.ArmConst;

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

public class hack extends AbstractJni {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;
    private DvmClass cNative;

    private hack () {
        emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.test").build();
        final Memory memory = emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));
        vm = emulator.createDalvikVM(new File("unidbg-android/src/test/java/com/hack/hack.apk"));
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/java/com/hack/libmyjni.so"), true);
        vm.setJni(this);
        vm.setVerbose(true);
        dm.callJNI_OnLoad(emulator);
        module = dm.getModule();

    }

    @Override
    public void setStaticIntField(BaseVM vm, DvmClass dvmClass, String signature, int value) {
        switch (signature) {
            case "com/gdufs/xman/MyApp->m:I":
                System.out.println("> Patched: com/gdufs/xman/MyApp->m:I");
                return;
        }
        super.setStaticIntField(vm, dvmClass, signature, value);
    }

    @Override
    public int getStaticIntField(BaseVM vm, DvmClass dvmClass, String signature) {
        switch (signature) {
            case "com/gdufs/xman/MyApp->m:I":
                System.out.println("> Patched: com/gdufs/xman/MyApp->m:I");
                return 0;
        }
        return super.getStaticIntField(vm, dvmClass, signature);
    }

    @Override
    public DvmObject<?> newObject(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        switch (signature) {
            case "com/gdufs/xman/MainActivity-><init>()V":
                System.out.println("> Patched: com/gdufs/xman/MainActivity-><init>()V");
                return vm.resolveClass("com/gdufs/xman/MainActivity").newObject(null);
        }
        return super.newObject(vm, dvmClass, signature, varArg);
    }

    @Override
    public void callVoidMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        switch (signature) {
            case "com/gdufs/xman/MainActivity->work(Ljava/lang/String;)V":
                System.out.println("> Patched: com/gdufs/xman/MainActivity->work(Ljava/lang/String;)V");
                return;
        }
        super.callVoidMethod(vm, dvmObject, signature, varArg);
    }

    public static void main(String[] args) {
        hack test = new hack();
        test.hookPuts();
        test.hookWork();
        test.saveSN();
        test.work();

    }


    private void saveSN() {
        List<Object> list = new ArrayList<>(10);
        list.add(vm.getJNIEnv());
        list.add(0);
        list.add(vm.addLocalObject(new StringObject(vm, "201608Am!2333")));   // arg 3

        Number number =  module.callFunction(emulator, 0x000011F8+1, list.toArray());
    }

    private void work() {
        DvmClass dvmClass = vm.resolveClass("com/gdufs/xman/MyApp");
        String methodSign = "work()V";
        DvmObject<?> dvmObject = dvmClass.newObject(null);

        DvmObject ret = dvmObject.callJniMethodObject(emulator, methodSign);
        Pointer pointer = emulator.getMemory().pointer(module.base + 0x00002EEB);

        System.out.println("> Pointer:"+pointer.getString(0x10));
    }


    private void hookPuts() {
        // hook saveSN中的f_puts函数
        HookZz hook = HookZz.getInstance(emulator);
        hook.replace(module.base + 0x00002C3C+1, new ReplaceCallback() {
            @Override
            public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
                System.out.println("> onCall:f_puts()");
                System.out.println("> arg0:"+context.getPointerArg(0).getString(0));  // 入参1 R0寄存器
                return super.onCall(emulator, context,originFunction);
            }
        }, true);
    }

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

            @Override
            public void postCall(Emulator<?> emulator, HookContext context) {
                System.out.println("postCall work");
                System.out.println(context.getPointerArg(0).getString(0));  // 入参1 R0寄存器
                super.postCall(emulator, context);
            }
        }, true);

    }
}

运行结果如下
请添加图片描述根据结果可以发现work中的函数是提示flag格式的,格式为xman{……},而且输入的sn即是flag,然后我们本应该输入的sn由异或运算可以得出为。

所以最终flag为:xman{201608Am!2333}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值