Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
dump上下文模拟执行doCommandNative方法
package com.kuaishou.android.security.internal.dispatch;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Backend;
import com.github.unidbg.arm.backend.CodeHook;
import com.github.unidbg.arm.backend.UnHook;
import com.github.unidbg.arm.backend.Unicorn2Factory;
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.linux.android.dvm.array.ArrayObject;
import com.github.unidbg.linux.android.dvm.wrapper.DvmBoolean;
import com.github.unidbg.linux.android.dvm.wrapper.DvmInteger;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.MemoryBlock;
import com.github.unidbg.pointer.UnidbgPointer;
import org.apache.commons.io.IOUtils;
import unicorn.ArmConst;
import unicorn.UnicornConst;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
public class JNICLibrary extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
JNICLibrary() {
emulator = AndroidEmulatorBuilder.for32Bit()
.setProcessName("com.smile.gifmaker")
.addBackendFactory(new Unicorn2Factory(true))
.build();
emulator.getSyscallHandler().setEnableThreadDispatcher(false);
final Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
vm = emulator.createDalvikVM();
vm.setJni(this);
vm.setVerbose(true);
}
public static void main(String[] args) throws Exception {
JNICLibrary mJNICLibrary = new JNICLibrary();
mJNICLibrary.load_context("unidbg-android/src/test/resources/DumpContext_20220808_000250");
mJNICLibrary.hook_libc();
mJNICLibrary.doCommandNative();
}
private void hook_libc() {
long libc_gettimeofday_addr = 3964436480L + 0x33534;
emulator.getBackend().hook_add_new(new CodeHook() {
@Override
public void hook(Backend backend, long address, int size, Object user) {
UnidbgPointer tv_ptr = emulator.getContext().getPointerArg(0);
ByteBuffer tv = ByteBuffer.allocate(8);
tv.order(ByteOrder.LITTLE_ENDIAN);
tv.putInt(0,1659890020);
tv.putInt(4, 2891054);
byte[] data = tv.array();
tv_ptr.write(0,data,0,8);
backend.reg_write(ArmConst.UC_ARM_REG_PC, backend.reg_read(ArmConst.UC_ARM_REG_LR).longValue());
}
@Override
public void onAttach(UnHook unHook) {
}
@Override
public void detach() {
}
}, libc_gettimeofday_addr, libc_gettimeofday_addr, null);
long libc_pthread_mutex_lock_addr = 3964436480L + 0x812EC;
emulator.getBackend().hook_add_new(new CodeHook() {
@Override
public void hook(Backend backend, long address, int size, Object user) {
backend.reg_write(ArmConst.UC_ARM_REG_R0, 0L);
backend.reg_write(ArmConst.UC_ARM_REG_PC, backend.reg_read(ArmConst.UC_ARM_REG_LR).longValue());
}
@Override
public void onAttach(UnHook unHook) {
}
@Override
public void detach() {
}
}, libc_pthread_mutex_lock_addr, libc_pthread_mutex_lock_addr, null);
long libc_pthread_mutex_unlock_addr = 3964436480L + 0x8166C;
emulator.getBackend().hook_add_new(new CodeHook() {
@Override
public void hook(Backend backend, long address, int size, Object user) {
backend.reg_write(ArmConst.UC_ARM_REG_R0, 0L);
backend.reg_write(ArmConst.UC_ARM_REG_PC, backend.reg_read(ArmConst.UC_ARM_REG_LR).longValue());
}
@Override
public void onAttach(UnHook unHook) {
}
@Override
public void detach() {
}
}, libc_pthread_mutex_unlock_addr, libc_pthread_mutex_unlock_addr, null);
long libc_malloc_addr = 3964436480L + 0x294F8;
emulator.getBackend().hook_add_new(new CodeHook() {
@Override
public void hook(Backend backend, long address, int size, Object user) {
int msize = backend.reg_read(ArmConst.UC_ARM_REG_R0).intValue();
MemoryBlock block = emulator.getMemory().malloc(msize, true);
backend.reg_write(ArmConst.UC_ARM_REG_R0, block.getPointer().toUIntPeer());
backend.reg_write(ArmConst.UC_ARM_REG_PC, backend.reg_read(ArmConst.UC_ARM_REG_LR).longValue());
}
@Override
public void onAttach(UnHook unHook) {
}
@Override
public void detach() {
}
}, libc_malloc_addr, libc_malloc_addr, null);
long libc_caloc_addr = 3964436480L + 0x2943C;
emulator.getBackend().hook_add_new(new CodeHook() {
@Override
public void hook(Backend backend, long address, int size, Object user) {
int num = backend.reg_read(ArmConst.UC_ARM_REG_R0).intValue();
int msize = backend.reg_read(ArmConst.UC_ARM_REG_R1).intValue();
MemoryBlock block = emulator.getMemory().malloc(num * msize, true);
backend.reg_write(ArmConst.UC_ARM_REG_R0, block.getPointer().toUIntPeer());
backend.reg_write(ArmConst.UC_ARM_REG_PC, backend.reg_read(ArmConst.UC_ARM_REG_LR).longValue());
}
@Override
public void onAttach(UnHook unHook) {
}
@Override
public void detach() {
}
}, libc_caloc_addr, libc_caloc_addr, null);
long libc_free_addr = 3964436480L + 0x29490;
emulator.getBackend().hook_add_new(new CodeHook() {
@Override
public void hook(Backend backend, long address, int size, Object user) {
backend.reg_write(ArmConst.UC_ARM_REG_PC, backend.reg_read(ArmConst.UC_ARM_REG_LR).longValue());
}
@Override
public void onAttach(UnHook unHook) {
}
@Override
public void detach() {
}
}, libc_free_addr, libc_free_addr, null);
long libcpp_patch_addr = 3620732928L + 0x87BB0;
emulator.getBackend().hook_add_new(new CodeHook() {
@Override
public void hook(Backend backend, long address, int size, Object user) {
backend.reg_write(ArmConst.UC_ARM_REG_PC, backend.reg_read(ArmConst.UC_ARM_REG_LR).longValue());
}
@Override
public void onAttach(UnHook unHook) {
}
@Override
public void detach() {
}
}, libcpp_patch_addr, libcpp_patch_addr, null);
@Override
public boolean callBooleanMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
switch (signature){
case "java/lang/Boolean->booleanValue()Z":{
return (boolean) dvmObject.getValue();
// return false;
}
}
return super.callBooleanMethodV(vm, dvmObject, signature, vaList);
}
int UNICORN_PAGE_SIZE = 0x1000;
private long align_page_down(long x){
return x & ~(UNICORN_PAGE_SIZE - 1);
}
private long align_page_up(long x){
return (x + UNICORN_PAGE_SIZE - 1) & ~(UNICORN_PAGE_SIZE - 1);
}
private void map_segment(long address, long size, int perms){
long mem_start = address;
long mem_end = address + size;
long mem_start_aligned = align_page_down(mem_start);
long mem_end_aligned = align_page_up(mem_end);
if (mem_start_aligned < mem_end_aligned){
emulator.getBackend().mem_map(mem_start_aligned, mem_end_aligned - mem_start_aligned, perms);
}
}
private void load_context(String dump_dir) throws IOException, DataFormatException, IOException {
Backend backend = emulator.getBackend();
Memory memory = emulator.getMemory();
String context_file = dump_dir + "\\" + "_index.json";
InputStream is = new FileInputStream(context_file);
String jsonTxt = IOUtils.toString(is, "UTF-8");
JSONObject context = JSONObject.parseObject(jsonTxt);
JSONObject regs = context.getJSONObject("regs");
backend.reg_write(ArmConst.UC_ARM_REG_R0, Long.decode(regs.getString("r0")));
backend.reg_write(ArmConst.UC_ARM_REG_R1, Long.decode(regs.getString("r1")));
backend.reg_write(ArmConst.UC_ARM_REG_R2, Long.decode(regs.getString("r2")));
backend.reg_write(ArmConst.UC_ARM_REG_R3, Long.decode(regs.getString("r3")));
backend.reg_write(ArmConst.UC_ARM_REG_R4, Long.decode(regs.getString("r4")));
backend.reg_write(ArmConst.UC_ARM_REG_R5, Long.decode(regs.getString("r5")));
backend.reg_write(ArmConst.UC_ARM_REG_R6, Long.decode(regs.getString("r6")));
backend.reg_write(ArmConst.UC_ARM_REG_R7, Long.decode(regs.getString("r7")));
backend.reg_write(ArmConst.UC_ARM_REG_R8, Long.decode(regs.getString("r8")));
backend.reg_write(ArmConst.UC_ARM_REG_R9, Long.decode(regs.getString("r9")));
backend.reg_write(ArmConst.UC_ARM_REG_R10, Long.decode(regs.getString("r10")));
backend.reg_write(ArmConst.UC_ARM_REG_R11, Long.decode(regs.getString("r11")));
backend.reg_write(ArmConst.UC_ARM_REG_R12, Long.decode(regs.getString("r12")));
backend.reg_write(ArmConst.UC_ARM_REG_SP, Long.decode(regs.getString("sp")));
backend.reg_write(ArmConst.UC_ARM_REG_LR, Long.decode(regs.getString("lr")));
backend.reg_write(ArmConst.UC_ARM_REG_PC, Long.decode(regs.getString("pc")));
backend.reg_write(ArmConst.UC_ARM_REG_CPSR, Long.decode(regs.getString("cpsr")));
backend.reg_write(ArmConst.UC_ARM_REG_FPSCR, Long.decode(regs.getString("fpscr")));
// 好像不设置这个也不会有什么影响
memory.setStackPoint(Long.decode(regs.getString("sp")));
backend.enableVFP();
JSONArray segments = context.getJSONArray("segments");
for (int i = 0; i < segments.size(); i++) {
JSONObject segment = segments.getJSONObject(i);
String path = segment.getString("name");
long start = segment.getLong("start");
long end = segment.getLong("end");
String content_file = segment.getString("content_file");
JSONObject permissions = segment.getJSONObject("permissions");
int perms = 0;
if (permissions.getBoolean("r")){
perms |= UnicornConst.UC_PROT_READ;
}
if (permissions.getBoolean("w")){
perms |= UnicornConst.UC_PROT_WRITE;
}
if (permissions.getBoolean("x")){
perms |= UnicornConst.UC_PROT_EXEC;
}
String[] paths = path.split("/");
String module_name = paths[paths.length - 1];
List<String> white_list = Arrays.asList(new String[]{"libkwsgmain.so", "libc.so", "[anon:stack_and_tls:19161]", "[anon:.bss]", "[vdso]", "[vvar]", "[anon:scudo:primary]", "libc++_shared.so", "[anon:scudo:secondary]"});
if (white_list.contains(module_name)){
int size = (int)(end - start);
map_segment(start, size, perms);
String content_file_path = dump_dir + "\\" + content_file;
File content_file_f = new File(content_file_path);
if (content_file_f.exists()){
InputStream content_file_is = new FileInputStream(content_file_path);
byte[] content_file_buf = IOUtils.toByteArray(content_file_is);
// 解压
Inflater decompresser = new Inflater();
decompresser.setInput(content_file_buf, 0, content_file_buf.length);
byte[] result = new byte[size];
int resultLength = decompresser.inflate(result);
decompresser.end();
backend.mem_write(start, result);
}
else {
System.out.println("not exists path=" + path);
byte[] fill_mem = new byte[size];
Arrays.fill( fill_mem, (byte) 0 );
backend.mem_write(start, fill_mem);
}
}
}
}
private void doCommandNative() {
// emulator.traceCode();
List<Object> list = new ArrayList<>(10);
list.add(vm.getJNIEnv()); // 第一个参数是env
DvmObject<?> thiz = vm.resolveClass("com/kuaishou/android/security/internal/dispatch/JNICLibrary").newObject(null);
list.add(vm.addLocalObject(thiz)); // 第二个参数,实例方法是jobject,静态方法是jclass,直接填0,一般用不到。
DvmObject<?> context = vm.resolveClass("com/yxcorp/gifshow/App", vm.resolveClass("android/app/Application")).newObject(null); // context
vm.addLocalObject(context);
list.add(10418); //参数1
StringObject urlObj = new StringObject(vm, "/rest/n/encode/androidffdb4a81067a6f7e20afbc3ec76652b3");
vm.addLocalObject(urlObj);
ArrayObject arrayObject = new ArrayObject(urlObj);
vm.addLocalObject(arrayObject);
StringObject appkey = new StringObject(vm,"d7b7d042-d4f2-4012-be60-d97ff2429c17");
vm.addLocalObject(appkey);
DvmInteger intergetobj = DvmInteger.valueOf(vm, -1);
vm.addLocalObject(intergetobj);
DvmBoolean boolobj = DvmBoolean.valueOf(vm, false);
vm.addLocalObject(boolobj);
StringObject whitestr = new StringObject(vm,"");
vm.addLocalObject(whitestr);
ArrayObject objlist = new ArrayObject(arrayObject, appkey, intergetobj, boolobj, context, null, boolobj, whitestr);
list.add(vm.addLocalObject(objlist));
// 这里获取 dump 时的 pc 地址作为模拟执行起始地址
long ctx_addr = emulator.getBackend().reg_read(ArmConst.UC_ARM_REG_PC).longValue();
// 开始模拟执行
Number result = Module.emulateFunction(emulator, ctx_addr + 1, list.toArray());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment