Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

无法在c++模拟AAssetManager* #62

Open
TTFGGF opened this issue Oct 23, 2019 · 20 comments
Open

无法在c++模拟AAssetManager* #62

TTFGGF opened this issue Oct 23, 2019 · 20 comments

Comments

@TTFGGF
Copy link

TTFGGF commented Oct 23, 2019

在jni中存在以下代码时程序会报错
jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
if (am != NULL) {
return am;
}

@zhkl0228
Copy link
Owner

使用VirtualModule试下

@zhkl0228
Copy link
Owner

带上测试用例跟so更直观

@TTFGGF
Copy link
Author

TTFGGF commented Oct 23, 2019

程序没有报错只是无法生成AssetManager* 因为GetLongField这个方法我传了一个随机值,因为AssetManager无法转化成功导致程序不跑后面逻辑了,我想知道怎样让这段代码reinterpret_cast<AssetManager*>(amHandle);能够正确转化

@TTFGGF
Copy link
Author

TTFGGF commented Oct 23, 2019

`package com.ks.app;

import cn.banny.unidbg.LibraryResolver;
import cn.banny.unidbg.arm.ARMEmulator;
import cn.banny.unidbg.file.FileIO;
import cn.banny.unidbg.file.IOResolver;
import cn.banny.unidbg.linux.android.AndroidARMEmulator;
import cn.banny.unidbg.linux.android.AndroidResolver;
import cn.banny.unidbg.linux.android.dvm.*;
import cn.banny.unidbg.linux.android.dvm.array.ArrayObject;
import cn.banny.unidbg.linux.android.dvm.array.ByteArray;
import cn.banny.unidbg.linux.file.ByteArrayFileIO;
import cn.banny.unidbg.linux.file.SimpleFileIO;
import cn.banny.unidbg.memory.Memory;
import cn.banny.unidbg.memory.MemoryBlock;
import cn.banny.utils.Hex;

import java.io.File;
import java.io.IOException;

public class TestSignSo1 extends AbstractJni implements IOResolver {

private static LibraryResolver createLibraryResolver() {
    return new AndroidResolver(19,"libc.so");
}

private static ARMEmulator createARMEmulator() {
    return new AndroidARMEmulator();
}

private final ARMEmulator emulator;
private final VM vm;

private final DvmClass Native;

private File APK_FILE = null;

private long address = 0;

@Override
public FileIO resolve(File workDir, String pathname, int oflags) {
    System.out.println("---" + pathname);
    if (pathname.equals("/sys/devices/system/cpu/online")) {
        return new SimpleFileIO(oflags, new File("src/main/resources/lib/online"), pathname);
    }
    if (pathname.equals("/proc/cpuinfo")) {
        return new SimpleFileIO(oflags, new File("src/main/resources/lib/cpuinfo"), pathname);
    }
    if (pathname.equals("/proc/mounts")) {
        return new SimpleFileIO(oflags, new File("src/main/resources/lib/mounts"), pathname);
    }
    if (pathname.equals("/proc/filesystems")) {
        return new SimpleFileIO(oflags, new File("src/main/resources/lib/filesystems"), pathname);
    }
    if (pathname.equals("/proc/self/auxv")) {
        return new ByteArrayFileIO(oflags, pathname, "".getBytes());
    }
    if (pathname.equals("/storage/emulated/0/sdk.txt")) {
        return new ByteArrayFileIO(oflags, pathname, "21".getBytes());
    }
    if (("/proc/self/status").equals(pathname)) {
        return new ByteArrayFileIO(oflags, pathname, "TracerPid:\t0\nState:\tr\n".getBytes());
    }
    if (("/proc/" + emulator.getPid() + "/stat").equals(pathname)) {
        return new ByteArrayFileIO(oflags, pathname, (emulator.getPid() + " (a.out) R 6723 6873 6723 34819 6873 8388608 77 0 0 0 41958 31 0 0 25 0 3 0 5882654 1409024 56 4294967295 134512640 134513720 3215579040 0 2097798 0 0 0 0 0 0 0 17 0 0 0\n").getBytes());
    }
    if (("/proc/" + emulator.getPid() + "/wchan").equals(pathname)) {
        return new ByteArrayFileIO(oflags, pathname, "sys_epoll".getBytes());
    }
    return null;
}

private TestSignSo1() throws IOException {
    emulator = createARMEmulator();
    emulator.getSyscallHandler().addIOResolver(this);
    final Memory memory = emulator.getMemory();
    MemoryBlock m = memory.malloc(10);
    address = m.getPointer().peer;
    memory.setLibraryResolver(createLibraryResolver());
    memory.setCallInitFunction();
    vm = emulator.createDalvikVM(APK_FILE);
    vm.setJni(this);
    DalvikModule dm = vm.loadLibrary(new File("src/main/resources/lib/libc.so"),false);
    dm = vm.loadLibrary(new File("src/main/resources/lib/libkwsgmain.so"), true);
    dm.callJNI_OnLoad(emulator);
    Native = vm.resolveClass("com.kuaishou.android.security.mainplugin.JNICLibrary".replace(".", "/"));
}

public void sign(){
    DvmObject context = vm.resolveClass("android.app.Application").newObject(null);
    String [] s1 = new String[]{"/rest/n/token/infra/getServiceTokenc369c4283cfc1f23de7c06aeb32c85b6"};
    ArrayObject arrayObject = new ArrayObject(new StringObject(vm, "/rest/n/token/infra/getServiceTokenc369c4283cfc1f23de7c06aeb32c85b6"));
    Number ret = Native.callStaticJniMethod(emulator, "doCommandNative(I[Ljava/lang/Object;)Ljava/lang/Object;",
            10412,
            new ArrayObject(null, new StringObject(vm, "d7b7d042-d4f2-4012-be60-d97ff2429c17"), null,null, context,null,null));
    long hash = ret.intValue() & 0xffffffffL;
    DvmObject dvmObject = vm.getObject(hash);
    System.out.println("hash:" + hash + ", dvmObject=" + dvmObject.getValue() + ", offset=" + (System.currentTimeMillis()) + "ms");
    vm.deleteLocalRefs();
}

public static void main(String[] args) throws Exception {
    TestSignSo1 testSignSo = new TestSignSo1();
    testSignSo.sign();
}

@Override
public void callStaticVoidMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    System.out.println("callStaticVoidMethodV=" + signature);
    if(vaList.getObject(0) != null){
        System.out.println("callStaticVoidMethodV=" + vaList.getObject(0).getValue());
    }
}

@Override
public DvmObject callObjectMethodV(BaseVM vm, DvmObject dvmObject, String signature, VaList vaList) {
    if("android.app.Application->getAssets()Landroid/content/res/AssetManager;".equals(signature)){
        return vm.resolveClass("android/content/res/AssetManager").newObject(null);
    }
    return super.callObjectMethodV(vm, dvmObject, signature, vaList);
}

@Override
public DvmObject callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    System.out.println("callStaticObjectMethodV=" + signature);
    if("java/lang/System->getProperty(Ljava/lang/String;)Ljava/lang/String;".equals(signature)){
        return new StringObject(vm, "2.1.0");
    }
    if("android.app.Application->getAssets()Landroid/content/res/AssetManager;".equals(signature)){
        return vm.resolveClass("android/content/res/AssetManager").newObject(null);
    }
    return null;
}

@Override
public DvmObject getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
    System.out.println("getStaticObjectField");
    return null;
}


@Override
public long getLongField(BaseVM vm, DvmObject dvmObject, String signature) {
    System.out.println("getLongField=" + signature);
    if("android/content/res/AssetManager->mObject:J".equals(signature)){
        return address;
    }
    return 0;
}

}

libc.zip
`

@zhkl0228
Copy link
Owner

返回的address不为0就可以跑后面的逻辑

@TTFGGF
Copy link
Author

TTFGGF commented Oct 24, 2019

但是JNI层AssetManager去读取资源文件好像是有问题的

@zhkl0228
Copy link
Owner

zhkl0228 commented Oct 24, 2019

``
Map<String, UnicornPointer> androidSymbols = new HashMap<>();
androidSymbols.put("AAssetManager_fromJava", svcMemory.registerSvc(new ArmSvc() {
@OverRide
public long handle(Emulator emulator) {
Pointer env = UnicornPointer.register(emulator, ArmConst.UC_ARM_REG_R0);
UnicornPointer assetManager = UnicornPointer.register(emulator, ArmConst.UC_ARM_REG_R1);
DvmObject obj = vm.getObject(assetManager.peer);
System.out.println("AAssetManager_fromJava env=" + env + ", assetManager=" + obj.getObjectType());
return assetManager.peer;
}
}));
androidSymbols.put("AAssetManager_open", svcMemory.registerSvc(new ArmSvc() {
@OverRide
public long handle(Emulator emulator) {
Arm32RegisterContext context = emulator.getContext();
Pointer amgr = context.getR0Pointer();
String filename = context.getR1Pointer().getString(0);
int mode = context.getR2Int();
System.out.println("AAssetManager_open amgr=" + amgr + ", filename=" + filename + ", mode=" + mode);
final int AASSET_MODE_STREAMING = 2;
final int AASSET_MODE_BUFFER = 3;
if (mode == AASSET_MODE_STREAMING || AASSET_MODE_BUFFER == mode) {
switch (filename) {
case "testAsset.txt":
byte[] data = vm.openAsset(filename);
MemoryBlock block = memory.malloc(data.length + 8, true);
block.getPointer().setInt(0, 0); // index
block.getPointer().setInt(4, data.length);
block.getPointer().write(8, data, 0, data.length);
return vm.addLocalObject(vm.resolveClass("android/content/res/Asset").newObject(block));
}
}
throw new UnicornException("filename=" + filename + ", mode=" + mode);
}
}));
androidSymbols.put("AAsset_close", svcMemory.registerSvc(new ArmSvc() {
@OverRide
public long handle(Emulator emulator) {
Arm32RegisterContext context = emulator.getContext();
UnicornPointer asset = context.getR0Pointer();
DvmObject obj = vm.getObject(asset.peer);
MemoryBlock block = (MemoryBlock) obj.getValue();
System.out.println("AAsset_close asset=" + asset + ", pointer=" + block.getPointer());
block.free(true);
return 0;
}
}));
androidSymbols.put("AAsset_getBuffer", svcMemory.registerSvc(new ArmSvc() {
@OverRide
public long handle(Emulator emulator) {
Arm32RegisterContext context = emulator.getContext();
UnicornPointer asset = context.getR0Pointer();
DvmObject obj = vm.getObject(asset.peer);
MemoryBlock block = (MemoryBlock) obj.getValue();
UnicornPointer buffer = block.getPointer().share(8, 0);
System.out.println("AAsset_getBuffer asset=" + asset + ", buffer=" + buffer);
return buffer.peer;
}
}));
androidSymbols.put("AAsset_getLength", svcMemory.registerSvc(new ArmSvc() {
@OverRide
public long handle(Emulator emulator) {
Arm32RegisterContext context = emulator.getContext();
UnicornPointer asset = context.getR0Pointer();
DvmObject obj = vm.getObject(asset.peer);
MemoryBlock block = (MemoryBlock) obj.getValue();
int length = block.getPointer().getInt(4);
System.out.println("AAsset_getLength asset=" + asset + ", length=" + length);
return length;
}
}));
androidSymbols.put("AAsset_read", svcMemory.registerSvc(new ArmSvc() {
@OverRide
public long handle(Emulator emulator) {
Arm32RegisterContext context = emulator.getContext();
UnicornPointer asset = context.getR0Pointer();
Pointer buf = context.getR1Pointer();
int count = context.getR2Int();
DvmObject obj = vm.getObject(asset.peer);
MemoryBlock block = (MemoryBlock) obj.getValue();
Pointer pointer = block.getPointer();
int index = pointer.getInt(0);
int length = pointer.getInt(4);
Pointer data = pointer.share(8, 0);
System.out.println("AAsset_read asset=" + asset + ", buf=" + buf + ", count=" + count);
int remaining = length - index;
int read = Math.min(remaining, count);
pointer.setInt(0, index + read);
byte[] bytes = data.getByteArray(index, read);
buf.write(0, bytes, 0, bytes.length);
return bytes.length;
}
}));
memory.loadVirtualModule("libandroid.so", androidSymbols);

@zhkl0228
Copy link
Owner

zhkl0228 commented Oct 24, 2019

加载自己的so之前,先参考以上添加虚拟模块

@TTFGGF
Copy link
Author

TTFGGF commented Oct 24, 2019

添加了可以了,但是碰到了新问题
private int faccessat(Unicorn u, Emulator emulator) { int dirfd = ((Number) u.reg_read(ArmConst.UC_ARM_REG_R0)).intValue(); Pointer pathname_p = UnicornPointer.register(emulator, ArmConst.UC_ARM_REG_R1); int oflags = ((Number) u.reg_read(ArmConst.UC_ARM_REG_R2)).intValue(); int mode = ((Number) u.reg_read(ArmConst.UC_ARM_REG_R3)).intValue(); String pathname = pathname_p.getString(0); if (log.isDebugEnabled()) { log.debug("faccessat dirfd=" + dirfd + ", pathname=" + pathname + ", oflags=0x" + Integer.toHexString(oflags) + ", mode=" + Integer.toHexString(mode)); } int ret = faccessat(emulator, pathname); if (ret == -1) { log.info("faccessat dirfd=" + dirfd + ", pathname=" + pathname + ", oflags=0x" + Integer.toHexString(oflags) + ", mode=" + Integer.toHexString(mode)); } return ret; }
这里面的pathname传递过来是乱码,不知道啥情况

@TTFGGF
Copy link
Author

TTFGGF commented Oct 24, 2019

faccessat这个函数模拟有问题,这里只判断了传入是文件路径的情况,还有一种是传入的是已经打开文件的句柄fd,flag=0情况应该是传入的是已经打开的fd还要通过get_dir(fd)才能获取具体路径把

@zhkl0228
Copy link
Owner

有问题的有能力修改就先修改,改好后再发个PR

@TTFGGF
Copy link
Author

TTFGGF commented Oct 24, 2019

只是发现了这个问题,目前还没这个能力改,等大佬来改

@zhkl0228
Copy link
Owner

好的,回头有时间再看下

@TTFGGF
Copy link
Author

TTFGGF commented Oct 24, 2019

大佬快点更新,卡在这里了。。。。

@zhkl0228
Copy link
Owner

最新的测试用例以及所涉及的文件打包发出来,我运行试下什么异常

@zhkl0228
Copy link
Owner

我用你以前发的测试,发现video_yh_loading_icon.png这个资源不知道在哪?最好把apk下载地址发我去下载

@TTFGGF
Copy link
Author

TTFGGF commented Oct 26, 2019

@zhkl0228
Copy link
Owner

检查了access系统调用没问题

@TTFGGF
Copy link
Author

TTFGGF commented Oct 26, 2019

AAsset_getLength asset=unicorn@0x7a92922, length=77861 AAsset_read asset=unicorn@0x7a92922, buf=unicorn@0x42683480, count=77861 AAsset_close asset=unicorn@0x7a92922, pointer=unicorn@0x400bd000 ���@� ���@� ���@� ���@�

群主没出现这个乱码,这个乱码应该不是文件地址,addIOResolver之后pathname返回这个乱码,这应该不是文件地址而是fd句柄把

@wyhuan
Copy link

wyhuan commented Mar 19, 2020

`package com.ks.app;

import cn.banny.unidbg.LibraryResolver;
import cn.banny.unidbg.arm.ARMEmulator;
import cn.banny.unidbg.file.FileIO;
import cn.banny.unidbg.file.IOResolver;
import cn.banny.unidbg.linux.android.AndroidARMEmulator;
import cn.banny.unidbg.linux.android.AndroidResolver;
import cn.banny.unidbg.linux.android.dvm.*;
import cn.banny.unidbg.linux.android.dvm.array.ArrayObject;
import cn.banny.unidbg.linux.android.dvm.array.ByteArray;
import cn.banny.unidbg.linux.file.ByteArrayFileIO;
import cn.banny.unidbg.linux.file.SimpleFileIO;
import cn.banny.unidbg.memory.Memory;
import cn.banny.unidbg.memory.MemoryBlock;
import cn.banny.utils.Hex;

import java.io.File;
import java.io.IOException;

public class TestSignSo1 extends AbstractJni implements IOResolver {

private static LibraryResolver createLibraryResolver() {
    return new AndroidResolver(19,"libc.so");
}

private static ARMEmulator createARMEmulator() {
    return new AndroidARMEmulator();
}

private final ARMEmulator emulator;
private final VM vm;

private final DvmClass Native;

private File APK_FILE = null;

private long address = 0;

@Override
public FileIO resolve(File workDir, String pathname, int oflags) {
    System.out.println("---" + pathname);
    if (pathname.equals("/sys/devices/system/cpu/online")) {
        return new SimpleFileIO(oflags, new File("src/main/resources/lib/online"), pathname);
    }
    if (pathname.equals("/proc/cpuinfo")) {
        return new SimpleFileIO(oflags, new File("src/main/resources/lib/cpuinfo"), pathname);
    }
    if (pathname.equals("/proc/mounts")) {
        return new SimpleFileIO(oflags, new File("src/main/resources/lib/mounts"), pathname);
    }
    if (pathname.equals("/proc/filesystems")) {
        return new SimpleFileIO(oflags, new File("src/main/resources/lib/filesystems"), pathname);
    }
    if (pathname.equals("/proc/self/auxv")) {
        return new ByteArrayFileIO(oflags, pathname, "".getBytes());
    }
    if (pathname.equals("/storage/emulated/0/sdk.txt")) {
        return new ByteArrayFileIO(oflags, pathname, "21".getBytes());
    }
    if (("/proc/self/status").equals(pathname)) {
        return new ByteArrayFileIO(oflags, pathname, "TracerPid:\t0\nState:\tr\n".getBytes());
    }
    if (("/proc/" + emulator.getPid() + "/stat").equals(pathname)) {
        return new ByteArrayFileIO(oflags, pathname, (emulator.getPid() + " (a.out) R 6723 6873 6723 34819 6873 8388608 77 0 0 0 41958 31 0 0 25 0 3 0 5882654 1409024 56 4294967295 134512640 134513720 3215579040 0 2097798 0 0 0 0 0 0 0 17 0 0 0\n").getBytes());
    }
    if (("/proc/" + emulator.getPid() + "/wchan").equals(pathname)) {
        return new ByteArrayFileIO(oflags, pathname, "sys_epoll".getBytes());
    }
    return null;
}

private TestSignSo1() throws IOException {
    emulator = createARMEmulator();
    emulator.getSyscallHandler().addIOResolver(this);
    final Memory memory = emulator.getMemory();
    MemoryBlock m = memory.malloc(10);
    address = m.getPointer().peer;
    memory.setLibraryResolver(createLibraryResolver());
    memory.setCallInitFunction();
    vm = emulator.createDalvikVM(APK_FILE);
    vm.setJni(this);
    DalvikModule dm = vm.loadLibrary(new File("src/main/resources/lib/libc.so"),false);
    dm = vm.loadLibrary(new File("src/main/resources/lib/libkwsgmain.so"), true);
    dm.callJNI_OnLoad(emulator);
    Native = vm.resolveClass("com.kuaishou.android.security.mainplugin.JNICLibrary".replace(".", "/"));
}

public void sign(){
    DvmObject context = vm.resolveClass("android.app.Application").newObject(null);
    String [] s1 = new String[]{"/rest/n/token/infra/getServiceTokenc369c4283cfc1f23de7c06aeb32c85b6"};
    ArrayObject arrayObject = new ArrayObject(new StringObject(vm, "/rest/n/token/infra/getServiceTokenc369c4283cfc1f23de7c06aeb32c85b6"));
    Number ret = Native.callStaticJniMethod(emulator, "doCommandNative(I[Ljava/lang/Object;)Ljava/lang/Object;",
            10412,
            new ArrayObject(null, new StringObject(vm, "d7b7d042-d4f2-4012-be60-d97ff2429c17"), null,null, context,null,null));
    long hash = ret.intValue() & 0xffffffffL;
    DvmObject dvmObject = vm.getObject(hash);
    System.out.println("hash:" + hash + ", dvmObject=" + dvmObject.getValue() + ", offset=" + (System.currentTimeMillis()) + "ms");
    vm.deleteLocalRefs();
}

public static void main(String[] args) throws Exception {
    TestSignSo1 testSignSo = new TestSignSo1();
    testSignSo.sign();
}

@Override
public void callStaticVoidMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    System.out.println("callStaticVoidMethodV=" + signature);
    if(vaList.getObject(0) != null){
        System.out.println("callStaticVoidMethodV=" + vaList.getObject(0).getValue());
    }
}

@Override
public DvmObject callObjectMethodV(BaseVM vm, DvmObject dvmObject, String signature, VaList vaList) {
    if("android.app.Application->getAssets()Landroid/content/res/AssetManager;".equals(signature)){
        return vm.resolveClass("android/content/res/AssetManager").newObject(null);
    }
    return super.callObjectMethodV(vm, dvmObject, signature, vaList);
}

@Override
public DvmObject callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    System.out.println("callStaticObjectMethodV=" + signature);
    if("java/lang/System->getProperty(Ljava/lang/String;)Ljava/lang/String;".equals(signature)){
        return new StringObject(vm, "2.1.0");
    }
    if("android.app.Application->getAssets()Landroid/content/res/AssetManager;".equals(signature)){
        return vm.resolveClass("android/content/res/AssetManager").newObject(null);
    }
    return null;
}

@Override
public DvmObject getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
    System.out.println("getStaticObjectField");
    return null;
}


@Override
public long getLongField(BaseVM vm, DvmObject dvmObject, String signature) {
    System.out.println("getLongField=" + signature);
    if("android/content/res/AssetManager->mObject:J".equals(signature)){
        return address;
    }
    return 0;
}

}

libc.zip
`

这个运行没有跑出结果 请问最后修改什么可以有结果输出?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants