当前位置:   article > 正文

攻防世界 黑客精神unidbg破解

unidbg

攻防世界 黑客精神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);

    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/158466
推荐阅读
相关标签
  

闽ICP备14008679号