一、目标
今天的我们来尝试载入某电商App的签名so文件来计算签名,在调用这个so的过程中有一些需要我们处理的坑,不过在之前的 AndroidNativeEmu模拟执行计算出某电商App sign 的教程中,我们已经了解了如何处理,不熟悉的同学可以复习下。
二、步骤
先把目标so放到我们的工程目录 /app/src/main/jniLibs 中,目录结构如下:
构造调用so签名函数的类
我们要调用这个 getSignFromJni 函数,就需要在我们的工程里面构造 com.xxx.common.utils.xxxUtils 这个类。
package com.xxx.common.utils;
import android.app.Application;
import android.content.Context;
public class xxxUtils {
// 载入 lib
static {
System.loadLibrary("xxxkit");
}
public static native String getSignFromJni(Context context, String str, String str2, String str3, String str4, String str5);
}
这里我们先用静态的方法自动载入so。然后调用 BitmapkitUtils.getSignFromJni函数。
duang…. 程序闪退。 我们从Logcat窗口看到如下报错信息:
JNI GetStaticObjectField called with pending exception java.lang.NoSuchFieldError: no "Landroid/app/Application;" field "a" in class "Lcom/xxx/common/utils/xxxUtils;" or its superclasses
哦,com.xxx.common.utils.xxxUtils 这类里面有个成员变量 a 类型是 android/app/Application, 没有找到。那就补上它,光补上还不行,从jadx的结果可以看到这个 a 变量是个静态成员,还需要初始化。 我们在 MyApp::onCreate()中初始化它:
public void onCreate() {
...
BitmapkitUtils.a = this;
...
}
继续执行,这次的报错是
JNI DETECTED ERROR IN APPLICATION: can't call android.content.pm.PackageManager android.content.ContextWrapper.getPackageManager() on null object
这个有点摸不着头脑,貌似是说有个null指针被访问了。这就体现之前学过 AndroidNativeEmu模拟执行计算出某电商App sign 的好处了,我们知道在so的 JNI_OnLoad 函数中, Application 这个对象被使用了。
说明 BitmapkitUtils.a = this; 这个初始化要在 载入so运行JNI_OnLoad之前。我们之前的做法是静态载入的so,JNI_OnLoad的函数执行要早于 BitmapkitUtils.a = this;, 所以我们改一下:
package com.xxx.common.utils;
import android.app.Application;
import android.content.Context;
public class xxxUtils {
public static Application a;
public static void loadso(){
try {
System.loadLibrary("jdbitmapkit");
}catch(Throwable ex){
ex.printStackTrace();
}
}
public static native String getSignFromJni(Context context, String str, String str2, String str3, String str4, String str5);
}
// MyApp::onCreate
public void onCreate() {
...
BitmapkitUtils.a = this;
BitmapkitUtils.loadso();
...
}
确保在loadso之前初始化好 a
开始Hook了
这so在做签名之前,会先检查自己的包名和包签名,所以我们要hook这两个函数,给它返回原本的值
// com/fenfei/loadso/SignatureHooker.java
@HookClass(Signature.class)
public class SignatureHooker {
@HookMethodBackup("toByteArray")
static Method onToByteArrayBackup;
@HookMethod("toByteArray")
public static byte[] onToByteArray(@ThisObject Signature thiz) throws Throwable {
Log.e("SignatureHooker", thiz + "hooked toByteArray success ");
return hexStringToBytes("30820247308201b0a00302010202044d6c5dae300d06092a.......");
}
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
}
// com/fenfei/loadso/MainActivityHooker.java
@HookClass(ContextWrapper.class)
public class MainActivityHooker {
@HookMethodBackup("getPackageName")
static Method onGetPackageNameBackup;
@HookMethod("getPackageName")
public static String onGetPackageName(@ThisObject ContextWrapper thiz) throws Throwable {
String strPkg = (String)SandHook.callOriginByBackup(onGetPackageNameBackup, thiz);
if (thiz.getClass().equals(MyApp.class)){
Log.e("MainActivityHooker", thiz + "hooked getPackageName success rc= com.xxx.app.mall");
return "com.xxx.app.mall";
}else{
return strPkg;
}
}
}
这次再调用下 BitmapkitUtils.getSignFromJni函数,就可以成功返回签名了
st=1608693949758&sign=1e1cd9e02f639fc4dacab8c71710bfd4&sv=111
但是如果不解决这个问题,so还是没法载入的。 在 借鸡生蛋之某电商App签名so的使用(三) 中我们介绍如何 Patch so 来填这个坑。
三、总结
看来借鸡生蛋还是不容易的,如果没有之前 AndroidNativeEmu模拟执行计算出某电商App sign 的经验,可能我们就已经放弃了。
不过这样间接的说明了AndroidNativeEmu和unidbg的价值,可以辅助我们分析so的执行流程。起码比直接面对Arm汇编要强。
关注微信公众号,最新技术干货实时推送