Skip to content

Commit

Permalink
iOS add WeChat7012Test
Browse files Browse the repository at this point in the history
  • Loading branch information
WebDucerBlog committed Jun 20, 2020
1 parent 22f0584 commit 557d7fe
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 5 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,21 @@ Simple tests under src/test directory

## More tests
- [unidbg-android/src/test/java/com/github/unidbg/android/QDReaderJni.java](https://github.com/zhkl0228/unidbg/blob/master/unidbg-android/src/test/java/com/github/unidbg/android/QDReaderJni.java)
- [unidbg-ios/src/test/java/com/github/unidbg/ios/WeChat7012Test.java](https://github.com/zhkl0228/unidbg/blob/master/unidbg-ios/src/test/java/com/github/unidbg/ios/WeChat7012Test.java)

## Features
- Emulation of the JNI Invocation API so JNI_OnLoad can be called.
- Support JavaVM, JNIEnv.
- Emulation of syscalls instruction.
- Support ARM32 and ARM64 bit.
- Support ARM32 and ARM64.
- Inline hook, thanks to [HookZz](https://github.com/jmpews/HookZz).
- Android import hook, thanks to [xHook](https://github.com/iqiyi/xHook).
- iOS [fishhook](https://github.com/facebook/fishhook) and substrate and [whale](https://github.com/asLody/whale) hook.
- Support simple console debugger, gdb stub, experimental IDA android debugger server, instruction trace, memory read/write trace.
- Support iOS objc and swift runtime.

## TODO
- ~~Working iOS emulation.~~
- ~~Add more iOS syscall.~~

## Thanks
- [unicorn](https://github.com/zhkl0228/unicorn)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ final void showHelp() {
System.out.println();
System.out.println("wx0-wx28, wfp, wip, wsp <value>: write specified register");
System.out.println("wb(address), ws(address), wi(address), wl(address) <value>: write (byte, short, integer, long) memory of specified address, address must start with 0x");
System.out.println("wx(address) <hex>: write bytes to memory of specified address, address must start with 0x");
System.out.println("wx(address) <hex>: write bytes to memory at specified address, address must start with 0x");
System.out.println();
System.out.println("b(address): add temporarily breakpoint, address must start with 0x, can be module offset");
System.out.println("b: add breakpoint of register PC");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ final void showHelp() {
System.out.println();
System.out.println("wr0-wr7, wfp, wip, wsp <value>: write specified register");
System.out.println("wb(address), ws(address), wi(address) <value>: write (byte, short, integer) memory of specified address, address must start with 0x");
System.out.println("wx(address) <hex>: write bytes to memory of specified address, address must start with 0x");
System.out.println("wx(address) <hex>: write bytes to memory at specified address, address must start with 0x");
System.out.println();
System.out.println("b(address): add temporarily breakpoint, address must start with 0x, can be module offset");
System.out.println("b: add breakpoint of register PC");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public final LoadedIpa load(String... loads) {
this.bundleVersion = parseVersion(ipa, appDir);
this.bundleIdentifier = parseCFBundleIdentifier(ipa, appDir);
} catch (IOException e) {
throw new IllegalStateException(e);
throw new IllegalStateException("load " + ipa.getAbsolutePath() + " failed", e);
}
this.executableBundlePath = generateExecutableBundlePath();
}
Expand Down
87 changes: 87 additions & 0 deletions unidbg-ios/src/test/java/com/github/unidbg/ios/WeChat7012Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.github.unidbg.ios;

import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.HookStatus;
import com.github.unidbg.file.ios.DarwinFileIO;
import com.github.unidbg.hook.HookContext;
import com.github.unidbg.hook.HookLoader;
import com.github.unidbg.hook.ReplaceCallback;
import com.github.unidbg.hook.fishhook.IFishHook;
import com.github.unidbg.hook.substrate.ISubstrate;
import com.github.unidbg.ios.hook.FishHook;
import com.github.unidbg.ios.ipa.IpaLoader;
import com.github.unidbg.ios.ipa.IpaLoader64;
import com.github.unidbg.ios.objc.ObjC;
import com.github.unidbg.ios.struct.objc.ObjcClass;
import com.github.unidbg.utils.Inspector;
import com.sun.jna.Pointer;

import java.io.File;

public class WeChat7012Test extends WeChatTest {

public static void main(String[] args) throws Exception {
new WeChat7012Test().test();
}

@Override
protected IpaLoader createLoader(File rootDir) {
return new IpaLoader64(new File("target/com.tencent.xin_7.0.12.ipa"), rootDir);
}

@Override
void init(Emulator<?> emulator) {
super.init(emulator);

IFishHook fishHook = FishHook.getInstance(emulator);
Module module = emulator.getMemory().findModule("WeChat");
fishHook.rebindSymbolImage(module, "strlen", new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
Pointer str = context.getPointerArg(0);
System.out.println("srlen str=" + str.getString(0) + ", LR=" + context.getLRPointer());
return super.onCall(emulator, context, originFunction);
}
});
fishHook.rebindSymbolImage(module, "memcpy", new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
Pointer dest = context.getPointerArg(0);
Pointer src = context.getPointerArg(1);
int size = context.getIntArg(2);
if (size > 0x50) {
size = 0x50;
}
Inspector.inspect(src.getByteArray(0, size), "memcpy src=" + src + ", dest=" + dest);
return super.onCall(emulator, context, originFunction);
}
});

HookLoader.load(emulator).hookObjcMsgSend(null);
}

@Override
protected void patch(Emulator<DarwinFileIO> emulator, ISubstrate substrate, ObjC objc) {
super.patch(emulator, substrate, objc);

ObjcClass cWCSDKAdapter = objc.getClass("WCSDKAdapter");
substrate.hookMessageEx(cWCSDKAdapter.getMeta(), objc.registerName("setup"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [WCSDKAdapter setup]");
return HookStatus.LR(emulator, 0);
}
});

ObjcClass cWAAdapterMgr = objc.getClass("WAAdapterMgr");
substrate.hookMessageEx(cWAAdapterMgr.getMeta(), objc.registerName("setup"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [WAAdapterMgr setup]");
return HookStatus.LR(emulator, 0);
}
});
}

}
226 changes: 226 additions & 0 deletions unidbg-ios/src/test/java/com/github/unidbg/ios/WeChatTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package com.github.unidbg.ios;

import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.Symbol;
import com.github.unidbg.arm.HookStatus;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.file.ios.DarwinFileIO;
import com.github.unidbg.hook.HookContext;
import com.github.unidbg.hook.ReplaceCallback;
import com.github.unidbg.hook.substrate.ISubstrate;
import com.github.unidbg.ios.hook.Substrate;
import com.github.unidbg.ios.ipa.EmulatorConfigurator;
import com.github.unidbg.ios.ipa.IpaLoader;
import com.github.unidbg.ios.ipa.LoadedIpa;
import com.github.unidbg.ios.objc.NSData;
import com.github.unidbg.ios.objc.ObjC;
import com.github.unidbg.ios.struct.objc.ObjcClass;
import com.github.unidbg.ios.struct.objc.ObjcObject;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.unix.UnixEmulator;
import com.github.unidbg.utils.Inspector;
import com.sun.jna.Pointer;
import org.apache.commons.codec.binary.Hex;

import java.io.File;
import java.util.concurrent.Callable;

public abstract class WeChatTest implements IOResolver<DarwinFileIO>, EmulatorConfigurator {

@Override
public FileResult<DarwinFileIO> resolve(Emulator<DarwinFileIO> emulator, String pathname, int oflags) {
if ("/private/jailbreak.txt".equals(pathname)) {
return FileResult.failed(UnixEmulator.EACCES);
}
return null;
}

@Override
public void configure(Emulator<DarwinFileIO> emulator, String executableBundlePath, File rootDir, String bundleIdentifier) {
emulator.getSyscallHandler().addIOResolver(this);
}

protected abstract IpaLoader createLoader(File rootDir);

final void test() throws Exception {
LoadedIpa loader = createLoader(new File("target/rootfs/wechat")).load(this);

final Emulator<DarwinFileIO> emulator = loader.getEmulator();
emulator.getSyscallHandler().addIOResolver(this);

ISubstrate substrate = Substrate.getInstance(emulator);
final ObjC objc = ObjC.getInstance(emulator);
patch(emulator, substrate, objc);

loader.setCallFinishLaunchingWithOptions(true);
loader.setIdentifierForVendor("00000000-8888-0000-0000-000000000000");
loader.setAdvertisingIdentifier("00000000-2222-0000-2222-000000000000");
loader.setCarrierName("CMCC");
loader.callEntry();
init(emulator);

ObjcClass cMMServiceCenter = objc.getClass("MMServiceCenter");
final ObjcObject serviceCenter = cMMServiceCenter.callObjc("defaultCenter");

ObjcClass cFPInitResponse = objc.lookUpClass("FPInitResponse");
if(cFPInitResponse != null) {
ObjcClass cNSData = objc.getClass("NSData");
byte[] bytes = Hex.decodeHex("0a06080012020a0012aa0412be020a8001693f613b673f386b6f3767356230346408555455040659580d0f510a06565805035206045055080631653e306c3033635a560206540655576135346132393433383832376130396163613630643561343737343461663831633564393262653806070006535051513c3a603c323d6b683436653e6764626806040f545d02520212b80144594501060000000e307185c4eeffff3001096c30030a450e070b8130040acf30050f970e070c830e070ed70e030d6a0e020c620e030bb60e010d6030060d230e040fcb30070ac230000b2a3006094f300109250e0308d20e030b76300308e1300409730e060cfc0e020fbd300009f630060dcb30010df030060ae630030be430070a0f30010d130e020f110e0609f530070e7b0e050d5030050ca330010baa0e020edf30030d8430030edd30020c430e0308e9eeb386001ae00130303064323233643365303430303030303130303030303030303030643731626130636536323034353362313931333530343564356635653230303030303030666338653634326362356234393164386130356135303034643439636638623935326331623831396462316464306666303039623032303338613664326163383935653932323531396137393134633731386135373162343934633731306463326464353733333333356238373666656232633738313837336564386133356431386433646538306263363432373233393563613033393736393437366465352084a38df305".toCharArray());
ObjcObject data = cNSData.callObjc("dataWithBytes:length:", bytes, bytes.length);
ObjcObject response = cFPInitResponse.callObjc("parseFromData:", data);

ObjcClass cProtobufCGIWrap = objc.getClass("ProtobufCGIWrap");
ObjcObject wrap = cProtobufCGIWrap.callObjc("new");
wrap.callObjc("setM_uiCgi:", 0xe3c); // fpInit
wrap.callObjc("setM_pbResponse:", response);

ObjcClass cFPManager = objc.getClass("FPManager");
ObjcObject fpManager = serviceCenter.callObjc("getService:", cFPManager);
fpManager.callObjc("updateResponse:Event:", wrap, 0);
}

doMore(emulator);

Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() {
long start = System.currentTimeMillis();
ObjcClass cMMClientCacheManager = objc.getClass("MMClientCacheManager");
ObjcObject clientCacheManager = serviceCenter.callObjc("getService:", cMMClientCacheManager);
ObjcObject basicData = clientCacheManager.callObjc("getBasicData");
NSData data = basicData.toNSData();
Inspector.inspect(data.getBytes(), "offset=" + (System.currentTimeMillis() - start) + "ms");
return null;
}
};
emulator.attach().run(callable);
}

protected void doMore(Emulator<DarwinFileIO> emulator) {}

void init(Emulator<?> emulator) {
Memory memory = emulator.getMemory();

final int kLevelAll = 0;
Module mars = memory.findModule("mars");
Symbol appender_set_console_log = mars.findSymbolByName("__Z24appender_set_console_logb", false);
Symbol xlogger_SetLevel = mars.findSymbolByName("_xlogger_SetLevel", false);
if (appender_set_console_log != null) {
appender_set_console_log.call(emulator, 1);
System.out.println("Call appender_set_console_log finished");
}
xlogger_SetLevel.call(emulator, kLevelAll);
System.out.println("Call xlogger_SetLevel finished");

Symbol __xlogger_Assert_impl = mars.findSymbolByName("___xlogger_Assert_impl", false);
ISubstrate substrate = Substrate.getInstance(emulator);
substrate.hookFunction(__xlogger_Assert_impl, new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
Pointer info = context.getPointerArg(0);
Pointer pointer = context.getPointerArg(2);
if (info != null && pointer != null) {
Pointer tag = info.getPointer(emulator.getPointerSize());
Pointer filename = info.getPointer(emulator.getPointerSize() * 2);
Pointer func_name = info.getPointer(emulator.getPointerSize() * 3);
int line = info.getInt(emulator.getPointerSize() * 4);
String sb = "__xloggerA[" + tag.getString(0) + "]" +
filename.getString(0) + "->" + func_name.getString(0) +
"@" + line + ": " +
pointer.getString(0);
System.err.println(sb);
}
return super.onCall(emulator, context, originFunction);
}
});
}

protected void patch(Emulator<DarwinFileIO> emulator, ISubstrate substrate, ObjC objc) {
ObjcClass cMMOOMCrashReport = objc.getClass("MMOOMCrashReport");
substrate.hookMessageEx(cMMOOMCrashReport.getMeta(), objc.registerName("checkRebootType"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [MMOOMCrashReport checkRebootType]");
return HookStatus.LR(emulator, 0);
}
});

ObjcClass cMemoryStatManager = objc.getClass("MemoryStatManager");
substrate.hookMessageEx(cMemoryStatManager.getMeta(), objc.registerName("sharedInstance"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [MemoryStatManager sharedInstance]");
return HookStatus.LR(emulator, 0);
}
});

ObjcClass cWCMatrixManager = objc.getClass("WCMatrixManager");
substrate.hookMessageEx(cWCMatrixManager.getMeta(), objc.registerName("sharedInstance"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [WCMatrixManager sharedInstance]");
return HookStatus.LR(emulator, 0);
}
});

ObjcClass cWCCrashBlockExtensionHandler = objc.getClass("WCCrashBlockExtensionHandler");
substrate.hookMessageEx(cWCCrashBlockExtensionHandler.getMeta(), objc.registerName("shareInstance"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [WCCrashBlockExtensionHandler shareInstance]");
return HookStatus.LR(emulator, 0);
}
});

ObjcClass cMMWatchDogMonitor = objc.getClass("MMWatchDogMonitor");
substrate.hookMessageEx(cMMWatchDogMonitor.getMeta(), objc.registerName("beginMonitor"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [MMWatchDogMonitor beginMonitor]");
return HookStatus.LR(emulator, 0);
}
});

ObjcClass cMicroMessengerAppDelegate = objc.getClass("MicroMessengerAppDelegate");
substrate.hookMessageEx(cMicroMessengerAppDelegate, objc.registerName("mainUISetting"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [MicroMessengerAppDelegate mainUISetting]");
return HookStatus.LR(emulator, 0);
}
});
substrate.hookMessageEx(cMicroMessengerAppDelegate, objc.registerName("shouldEnterSafeMode"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [MicroMessengerAppDelegate shouldEnterSafeMode]");
return HookStatus.LR(emulator, 0);
}
});
substrate.hookMessageEx(cMicroMessengerAppDelegate, objc.registerName("beforeMainLaunching"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [MicroMessengerAppDelegate beforeMainLaunching]");
return HookStatus.LR(emulator, 0);
}
});
substrate.hookMessageEx(cMicroMessengerAppDelegate, objc.registerName("continueMainLaunching:"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [MicroMessengerAppDelegate continueMainLaunching]");
return HookStatus.LR(emulator, 0);
}
});

ObjcClass cMMSafeModeInfo = objc.getClass("MMSafeModeInfo");
substrate.hookMessageEx(cMMSafeModeInfo.getMeta(), objc.registerName("shareInstance"), new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("Patch [MMSafeModeInfo shareInstance]");
return HookStatus.LR(emulator, 0);
}
});
}

}

0 comments on commit 557d7fe

Please sign in to comment.