这是我们的运行时的最后几句日志,可以看到最后是通过JNIENV->NewStringUTF构造了返回的字符串,地址为0x26a34,我们在IDA中跳转到该地址
这句代码也就是newstringutf函数,那么这里的v5的类型肯定就是JNIEnv*了,我们可以先按y去转一下v5的类型
现在还原回来了。我们继续分析,可以看到该值是有v138转换而来的,所以我们下一步就是要去分析v138的来源了。继续往上看,我们注意到了5065行的
熟悉c语言的朋友肯定知道,这是在往v138里面写入v727和v132,其中v727是固定的M,后面的v132则是通过前面加密得到的结果。所以v132也就是我们的分析目标
继续往上看
发现
v132貌似是通过base64编码得到的,我们现在需要去验证base64_encode
这个函数是否是标准的base64(及其入参与标准bas64解密v132的结果是否一致)
这是base64_encode处的汇编代码,我们只需要0x268cc处下断点,查看x0寄存器(v123,即该函数的入参)的值
这和我们网站上进行在线解base64的结果是一样的,所以毋庸置疑这就是标准的base64,而其中的v123是base64的入参,这样的话base64_encode这个函数里面的逻辑我们就不用去看了。我们的下一步的目标就是要去分析v123所在地址内容的来源
我们去trace v123当前所在地址的写入(0x1256400,0x1256400+0x01A0),来看这串字符串到底是在哪里写入的
我们可以注意到,0x7a6d6e2579331dae 不就是我们之前base64入参前几个字节的大端序吗,所以写入是在0xa07c这个地址写入的。
但是貌似都是一组一组的进行写入的,0xa128、0xa128(后面都变为了0xa150),0xa07c、0xa07c;这样 0xa07c处写入的值可能与之前的0xa128处的值是有一定联系的。我们进入到IDA中去看这两个地址
首先是0xa128(位于WBACRAES128_EncryptCBC
函数中)
然后是0xa07c(位于WBACRAES_EncryptOneBlock
函数中)
0xa128这个地址处是在进行veorq_s8(*v6,this[1]), 了解veorq_s8这个函数的朋友肯定知道(不了解也没关系哈,可以问一下gpt),这就是在对v6和this[1]进行按位异或。不过目前我们也不懂这是在干嘛,为什么要这样做;
我们暂且先按下不表,继续去看第二处0xa07c,哦,这里我们注意到在这个写入的上方刚刚才进行了AES_EncryptOneBlock(翻译过来是 AES_加密一个块),这不明摆着告诉我们是一个AES了,似乎还是个白盒AES。
那前面的0xa128又是在干嘛呢,这不也很闲而已见了,大概率是在进行AES前的初始化(在CBC模式中AES分组后每组加密前都要先与前一轮得到的密文进行异或,第一轮的明文与IV进行异或),所以这又极可能是个CBC的加密模式(这个现在只是猜想,我们待会儿会来验证)
okay,现在我们已经明确了这个加密算法是个AES了,并且在WBACRAES128_EncryptCBC
每完成一块加密明文的初始化后都会进入到WBACRAES_EncryptOneBlock
中进行一个块的加密
接着我们去验证上面的猜想
我们可以分别对WBACRAES128_EncryptCBC
和WBACRAES_EncryptOneBlock
调用处进行hook,观察其入参(第一处是AES最原始的入参,而第二处则可能是已经经历过填充、第一轮加密前的对第一块明文初始化(与IV进行异或操作)的入参了)
先看第一处,我们先来确认一下最原始的入参是什么
在WBACRAES128_EncryptCBC
上按X
键,找到引用他的地址,发现有两处,我们该如何确认究竟是被哪个函数调用的呢?很简单,我们可以在两个函数跳转处都下上断点,看看究竟是在哪个地方断到了,那么就是哪个函数调用的
好,我们说做就做
在加过断点并且重新运行后发现只有在encrypt1这个函数中会断下来,在encrypt2中是断不下来的。
那我们接着看入参,上面这张图是encrypt1中跳转进入WBACRAES128_EncryptCBC
附近的代码,其中的x1寄存器存放了我们的入参(这是如何确定的呢?因为之前在WBACRAES128_EncryptCBC
函数里面是在用v6跟this[1]进行异或且结果赋给了a6,所以a6就是入参,a6又是由这里的a2赋值而来的,而a2在encrypt1对应的是a1这个参数,在a1这个地方按Tab键反汇编可以发现其对应的寄存器是x1)
运行断下之后
我们可以看到这不就是我们给unidbg的第一个字符串吗?不对,多了一个checkcode,并且每次重新运行时这个checkcode都是会变化的,所以我们又多了一个分析目标checkcode,不过现在还轮不到他,他得先往后稍稍。
所以AES的入参我们其实已经可以确定了,就是我们传给unidbg的第一个字符串+&checkcode=....(距离还原sd又近了一步...)
接下来我们去看WBACRAES_EncryptOneBlock
,这个函数是在WBACRAES128_EncryptCBC
中被引用的,我们直接在跳转处下断点
okay,下了断点运行后打印x1寄存器中的内容,发现...好熟悉...这不是上面那种unidbg运行结果图中的内容吗,诶,不对,又多了一个02 02,这似乎是AES进行了填充(当AES明文长度不是16的倍数时,在加密前会进行填充)。填充了02 02,此前长度距离16的整数倍也差了两个字节,这不是PKCS7的填充模式吗(PKCS7填充模式会填充(16-length%16)个(16-length%16) )。
那这样就说得通了,我们现在可以确认填充模式是PKCS7了。
但是我总感觉少了些什么,我记得在进入这个函数之前好像做过异或操作呀,但这里的前16个字节怎么还是原始数据呢,好奇怪呀,那我们再拐回头去看一下那个函数(WBACRAES128_EncryptCBC
)吧
其实这里的异或逻辑其实有两个分支,其中上面的只进行了一轮的写入,后面的轮次都是在下方地址这个写入的
我们可以猜想,第一轮异或时的this[1]可能为0(任何数异或0的结果都还是它本身),后面轮次异或中的v11为上一轮加密产生的密文。
我们看第一次运行到0xa150这个地方时的v11是否为我们上一轮加密的结果(第一轮异或的地方这里就不再验证了,大家可以自己验证一下),如果是的话,那么加密模式和IV我们也就确认了。
这是0xa150处的汇编,我们只需要在这个0xa14c地方下断点然后去看异或前q0,q1寄存器中的内容(这里的Q寄存器是通用向量寄存器)
可以看到q0寄存器中的内容跟我们进行过第一轮加密后的密文内容是一致的,所以我们的猜想正确。
所以现在我们直径知道加密模式是CBC,IV为0x000000000000了,接下来我们就要去获取AES的key了
我们回到这个函数中,双击函数中黄色的那个地方,跳转到具体的函数中去
里面是这样的,但是我们无论如何都无法继续跳转进去了,我们按TAB把他转换为汇编
发现这里其实是混淆过的了,最后是通过
这条指令跳转到下一个函数中去了,因为IDA无法解析出运行时X4寄存器的内容,所以我们双击也无法进入。现在怎么办?怎么办?okay,那么第一种处理方式就是去混淆(可以把外面的控制流混淆也顺便给去了...);第二种方式呢,就是在这个地方下个断点,去看在这里断住时的X4寄存器的内容。 本人比较菜,选择第二种方式(不得不说,unidbg对于还原算法来说真是一个好工具)。
okay,nice!我们现在知道了其在so中的偏移为0x86f8。换不多说,我们直接在IDA中跳转过去。
废了九牛二虎之力我们终于进来了
里面似乎都是在查表进行替换,这不就是查表法AES吗,我们点进去后可以发现这个表好像有些大,而且我们似乎也找不到key的逻辑,那..这是个白盒AES了。
对于白盒AES来说,我们的处理方法有两种,第一中就是把代码和表全扣下来;第二种呢就是DFA攻击白盒AES得到秘钥后还原算法。
这里我们选择第二种方式,这里的白盒AES也是一个比较标准的白盒AES。
首先我们要稍微了解一些如何使用DFA攻击白盒AES得到轮秘钥。原理性的东西这里也就不提了(网上也有很多相关文章,大家感兴趣的话可以去看一下)。这里只说怎么去做,白盒AES我们通常是要找到倒数第二轮(在这里aes-128中是第九轮)的入口处去多次修改我们明文的单个字节,通过修改单个字节得到的加密结果与正常的加密结果进行碰撞就可以确定出部分第十轮子密钥,最后只要增加样本数,就能还原出第十轮的紫秘钥了,然后通过秘钥回推就可以得到初始秘钥了。
大家也不用害怕自己不会写这些东西,因为已经有开源的项目了。
现在,我们先去寻找第九轮加密,看下面这段代码
这里的v48表示表示当前循环次数,每一块的前九轮加密都在这个循环体中,并且每一轮都会经过
这句代码,所以我们完全可以去在这句代码处下一个断点并重写OnHit,当这句代码经过九次时,我们去改变这轮加密的明文,用新产生的密文与正常密文进行碰撞。这样最终就能得到我们的第十轮子密钥了。由于AES是按块进行加密的,其中每个块加密时的轮秘钥都是相同的,所以我们也只需要去观察一个块的加密即可,这里我们选择第一个块。
那么我们该如何去修改加密的明文呢?我们需要先得到运行时所加密明文的地址
我们观察到在每一块的AES加密时最初进行的是一个PrepareAESMatrix
函数,这是在做加密前的矩阵的初始化准备操作
我们进来后可以看出a3中最后存放存放了我们之后要去加密的数据,所以我们现在的目标就是获取a3的地址
我们在0x7908处下断点,去观察x2寄存器此时所在地址
可以看到这确实是在做矩阵变换的操作。做完矩阵变换后的明文地址为0xe4ffeb10,这是我们dfa时要去修改的地方。下面是dfaattach这段代码的写法
我们之前提到过dfa攻击时要使用用正常加密结果生成的密文和改变一字节明文后加密得到的密文进行碰撞,所以我们需要去trace 密文的写入。还记不记得我们每轮密文写入的地址了,我们在识别AES中这一步中已经获得过了,是(0x1256400,0x1256400+0x01A0)这块地址,我们加上这句代码重新运行,但是发现很奇怪,并没有trace相关的日志。我们已经trace不到了,这是为什么?我们尝试重新去hook base64_encode这个函数,重新查看数据所在的地址
我们可以发现到地址竟然发生了变化,这又是为什么?可能是因为我文章写的时间间隔太久了?我也不是很清楚。但是没关系,我们重新去trace(0x1255a380,0x1255a380+0x01A0);
上图为dfa注入前第一块的加密结果,下图为dfa注入后第一块的加密结果。
可以看到,有四个字节发生了变化,这就证明我们的注入是对的。
我们尝试使用phoenixAES
这个库来完成轮秘钥的分析(使用时需要注入多组故障密文已完成秘钥分析)
这样我们就成功的获取到了第十轮的轮秘钥,由于AES加密算法轮秘钥生成的特型,有第i轮的轮秘钥是可以推出i-1轮的轮秘钥,以此类推,可以得到初始秘钥(由于篇幅问题,具体原理这里不再解释,有兴趣的朋友可以自行了解)。下面给出相关代码
成功运行,这样我们也获取到AES的key了。
我们已经还原出AES的所有内容了,但是似乎又少了什么,对了,我们的checkcode还没有分析呢,这是个动态的32字节的值。
从哪里开始呢,我依稀记得checkcode最先出现在了白盒AES的入参中的,可以尝试通过hook白盒AES入口函数得到checkcode字符相对应的地址,再去trace这个地址的写入。我们去试一下
首先,先去hook白盒AES入口处
可以看到,checkcode字段的内容对应的地址大概是在0x1255a380+0x15e~0x1255a380+0x17d,我们去trace这段地址的写入
大概是在这一块,对应的so偏移地址是0x29bac。
在IDA跳转到这块地址之后
发现是将v472中的内容写入到了这里,向上看v472,又是通过v469来的,继续向上看v469似乎又是通过v116来的。
继续向上看,发现v116是通过v108来的,而v108似乎是通过4697行的sprintf写入的,但是继续向上看
发现有好几个通过sprintf向v108中写入的函数(上面还有两个),回忆一下之前AES的入参od=gogle&checkcode=
通过该入参格式我们就已经可以判断出是在4665这一行中写入的(如果当时没看出来怎么办,没关系的,可以在这几个sprintf出都下上断点,看看是在哪个地方断住了)
确实在这个地方断住了,并且x3也就是p跟后面的AES入参checkcode内容是一致的。
okay,这样就确定了这个p就是checkcode的来源,现在我们需要去找这个p的赋值逻辑
按下X键我们可以看到哪个地方引用了这个p,似乎是在4567行对p进行了赋值
但是这四句代码好像是在对p进行换位的逻辑,并不是给p赋值的地方(这也说明了p经过上一步的加密后是有一部内部的换位操作的)
我们继续向上看,有个endText函数,我们先跳转过去,在这个函数处下个断点
可以看到确实在这里端住了,并且在进入到这个函数之前,x0寄存器(也就是p)是空的,证实了p确实是有这个函数生成的;
其中的第二个参数v68的内容是这样的(经过多次运行验证发现是个定值(是对包名做了md5,有兴趣的话大家可以自己去跟一下))
现在我们进入到endText里面去看看具体的逻辑
进来之后发现,好家伙,全是混淆,这我怎么下手。别急,我们先在入参处按X键,去找a1(也就是p)的生成逻辑
可以看到,最后是将a1赋值给了v320(由于a1是个char*也就是指针类型,所以这句代码也相当于是将v320指向了a1所指向的内存,这样后续修改v320,也就相当于修改a1了),可以的,我们去看v320好了。
跳转过去发现,这似乎已经是在做最后的写入操作了,而且写的来源是v556,而v556来源于v546,所以下一步我们要去看v546。
在v546处按下X键,随便进入跳转一个,发现似乎是在进行md5了,而且还有很多虚假控制流,这很难看啊,md5的参数又是什么呢。别急,不要忘了入参中还有另外一个,这个入参不可能毫无用处,我们去看看对他进行了什么操作。
在a2处按下X键,只有一处,我们直接跳转过去
这里是在往s里面写东西,往下面稍微看一下就知道是在对s进行md5(是否魔改目前还未知)加密操作了。其中的a2(一个定值)是一个字符串,v9是time(0)(这是个时间戳)。
我们在完成对s的写入操作后下一个断点去看看其内容
发现就是一个定值加一个时间戳。我们下一步验证endText的结果是否与对其进行标准md5一致。
可以发现我们在网站上进行的md5似乎跟写入checkcode中的不...,一样的。只不过调整了顺序,大家是否还记得之前有个对p进行内部换位的操作,那这不就对应上了吗。
所以checkcode就是对 6cf70fabc636f5e6569cd03e194e5769+现在的时间戳
进行标准的md5后调整顺序 (即checkcode=p[12:16]+p[4:12]+p[0:4])。这样checkcode也就分析完成了。
okay,好了,这篇文章写的陆陆续续的,花费了大概3天时间终于也是写完了,个人感觉该案例难度中等,希望对大家能够有所帮助,有什么不好的地方也请大家多多指出。
import
com.github.unidbg.AndroidEmulator;
import
com.github.unidbg.Emulator;
import
com.github.unidbg.Module;
import
com.github.unidbg.arm.backend.Unicorn2Factory;
import
com.github.unidbg.debugger.BreakPointCallback;
import
com.github.unidbg.debugger.Debugger;
import
com.github.unidbg.file.FileResult;
import
com.github.unidbg.file.IOResolver;
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.file.ByteArrayFileIO;
import
com.github.unidbg.memory.Memory;
import
com.github.unidbg.memory.MemoryBlock;
import
com.github.unidbg.pointer.UnidbgPointer;
import
org.apache.commons.io.HexDump;
import
unicorn.Arm64Const;
import
unicorn.ArmConst;
import
javax.xml.transform.Source;
import
java.io.*;
import
java.nio.charset.StandardCharsets;
import
java.util.ArrayList;
import
java.util.List;
import
java.util.Random;
public
class
mwzzzh
extends
AbstractJni
implements
IOResolver {
private
final
AndroidEmulator emulator;
// private final DvmClass CryptoTool;
private
final
VM vm;
public
final
Module module;
public
mwzzzh()
throws
IOException{
//进行初始化
emulator = AndroidEmulatorBuilder
.for64Bit()
.addBackendFactory(
new
Unicorn2Factory(
true
))
.setProcessName(
"com.cloudy.linglingbang"
)
.build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(
new
AndroidResolver(
23
));
vm = emulator.createDalvikVM(
new
File(
"D:\\xinjianwenjianjia\\anzhuonixiang\\unidbg\\unidbg\\unidbg-android\\src\\test\\java\\com\\wulinglogin\\8.2.4.apk"
));
//改成自己的apk路径
vm.setJni(
this
);
vm.setVerbose(
true
);
emulator.getSyscallHandler().addIOResolver(
this
);
DalvikModule dm2 = vm.loadLibrary(
"encrypt"
,
true
);
module = dm2.getModule();
// CryptoTool = vm.resolveClass("com.bangcle.CryptoTool");
dm2.callJNI_OnLoad(emulator);
}
public
static
void
main(String[] args)
throws
Exception {
mwzzzh test =
new
mwzzzh();
test.call_checkcode();
}
public
void
call_checkcode(){
List<Object> list =
new
ArrayList<>(
5
);
list.add(vm.getJNIEnv());
// 第一个参数是env
list.add(
0
);
// 第二个参数,实例方法是jobject,静态方法是jclazz,可以填0,但最好是构造一下
list.add(vm.addLocalObject(
new
StringObject(vm,
"mobile=1475&password=123456&client_id=2019041810222516127&client_secret=c5ad2a4290faa3df39683865c2e10310&state=CstGrOjmnN&response_type=token&ostype=ios&imei=00&mac=00:00:00:00:00:00&model=Pixel 6&sdk=33&serviceTime=1745556662765&mod=google"
)));
list.add(
2
);
list.add(vm.addLocalObject(
new
StringObject(vm,
"1745556662765"
)));
Number retNum = module.callFunction(emulator,
0x25250
, list.toArray());
String ret = vm.getObject(retNum.intValue()).getValue().toString();
System.out.println(
"结果->"
+ ret);
}
@Override
public
FileResult resolve(Emulator emulator, String pathname,
int
oflags) {
System.out.println(
"open path: "
+pathname);
return
null
;
}
@Override
public
DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
switch
(signature){
case
"android/app/ActivityThread->currentActivityThread()Landroid/app/ActivityThread;"
:{
// 创建一个假的 ActivityThread 实例返回
return
vm.resolveClass(
"android/app/ActivityThread"
).newObject(
null
);
}
}
return
super
.callStaticObjectMethod(vm, dvmClass, signature, varArg);
}
@Override
public
DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
switch
(signature) {
case
"android/app/ActivityThread->getSystemContext()Landroid/app/ContextImpl;"
:{
return
vm.resolveClass(
"android/app/ContextImpl"
).newObject(
null
);
}
case
"android/app/ContextImpl->getPackageManager()Landroid/content/pm/PackageManager;"
:{
return
vm.resolveClass(
"android/content/pm/PackageManager"
).newObject(
null
);
}
}
return
super
.callObjectMethod(vm, dvmObject, signature, varArg);
}
@Override
public
DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
switch
(signature) {
case
"android/os/Build->MODEL:Ljava/lang/String;"
:{
return
new
StringObject(vm,
"Pixel 6"
);
}
case
"android/os/Build->MANUFACTURER:Ljava/lang/String;"
:{
return
new
StringObject(vm,
"google"
);
}
case
"android/os/Build$VERSION->SDK:Ljava/lang/String;"
:{
return
new
StringObject(vm,
"29"
);
}
}
return
super
.getStaticObjectField(vm, dvmClass, signature);
}
package
com.wulinglogin1;
import
com.github.unidbg.AndroidEmulator;
import
com.github.unidbg.Emulator;
import
com.github.unidbg.Module;
import
com.github.unidbg.arm.backend.Unicorn2Factory;
import
com.github.unidbg.debugger.BreakPointCallback;
import
com.github.unidbg.debugger.Debugger;
import
com.github.unidbg.file.FileResult;
import
com.github.unidbg.file.IOResolver;
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.file.ByteArrayFileIO;
import
com.github.unidbg.memory.Memory;
import
com.github.unidbg.memory.MemoryBlock;
import
com.github.unidbg.pointer.UnidbgPointer;
import
org.apache.commons.io.HexDump;
import
unicorn.Arm64Const;
import
unicorn.ArmConst;
import
javax.xml.transform.Source;
import
java.io.*;
import
java.nio.charset.StandardCharsets;
import
java.util.ArrayList;
import
java.util.List;
import
java.util.Random;
public
class
mwzzzh
extends
AbstractJni
implements
IOResolver {
private
final
AndroidEmulator emulator;
// private final DvmClass CryptoTool;
private
final
VM vm;
public
final
Module module;
public
mwzzzh()
throws
IOException{
//进行初始化
emulator = AndroidEmulatorBuilder
.for64Bit()
.addBackendFactory(
new
Unicorn2Factory(
true
))
.setProcessName(
"com.cloudy.linglingbang"
)
.build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(
new
AndroidResolver(
23
));
vm = emulator.createDalvikVM(
new
File(
"D:\\xinjianwenjianjia\\anzhuonixiang\\unidbg\\unidbg\\unidbg-android\\src\\test\\java\\com\\wulinglogin\\8.2.4.apk"
));
//改成自己的apk路径
vm.setJni(
this
);
vm.setVerbose(
true
);
emulator.getSyscallHandler().addIOResolver(
this
);
DalvikModule dm2 = vm.loadLibrary(
"encrypt"
,
true
);
module = dm2.getModule();
// CryptoTool = vm.resolveClass("com.bangcle.CryptoTool");
dm2.callJNI_OnLoad(emulator);
}
public
static
void
main(String[] args)
throws
Exception {
mwzzzh test =
new
mwzzzh();
test.call_checkcode();
}
public
void
call_checkcode(){
List<Object> list =
new
ArrayList<>(
5
);
list.add(vm.getJNIEnv());
// 第一个参数是env
list.add(
0
);
// 第二个参数,实例方法是jobject,静态方法是jclazz,可以填0,但最好是构造一下
list.add(vm.addLocalObject(
new
StringObject(vm,
"mobile=1475&password=123456&client_id=2019041810222516127&client_secret=c5ad2a4290faa3df39683865c2e10310&state=CstGrOjmnN&response_type=token&ostype=ios&imei=00&mac=00:00:00:00:00:00&model=Pixel 6&sdk=33&serviceTime=1745556662765&mod=google"
)));
list.add(
2
);
list.add(vm.addLocalObject(
new
StringObject(vm,
"1745556662765"
)));
Number retNum = module.callFunction(emulator,
0x25250
, list.toArray());
String ret = vm.getObject(retNum.intValue()).getValue().toString();
System.out.println(
"结果->"
+ ret);
}
@Override
public
FileResult resolve(Emulator emulator, String pathname,
int
oflags) {
System.out.println(
"open path: "
+pathname);
return
null
;
}
@Override
public
DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
switch
(signature){
case
"android/app/ActivityThread->currentActivityThread()Landroid/app/ActivityThread;"
:{
// 创建一个假的 ActivityThread 实例返回
return
vm.resolveClass(
"android/app/ActivityThread"
).newObject(
null
);
}
}
return
super
.callStaticObjectMethod(vm, dvmClass, signature, varArg);
}
@Override
public
DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
switch
(signature) {
case
"android/app/ActivityThread->getSystemContext()Landroid/app/ContextImpl;"
:{
return
vm.resolveClass(
"android/app/ContextImpl"
).newObject(
null
);
}
case
"android/app/ContextImpl->getPackageManager()Landroid/content/pm/PackageManager;"
:{
return
vm.resolveClass(
"android/content/pm/PackageManager"
).newObject(
null
);
}
}
return
super
.callObjectMethod(vm, dvmObject, signature, varArg);
}
@Override
public
DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
switch
(signature) {
case
"android/os/Build->MODEL:Ljava/lang/String;"
:{
return
new
StringObject(vm,
"Pixel 6"
);
}
case
"android/os/Build->MANUFACTURER:Ljava/lang/String;"
:{
return
new
StringObject(vm,
"google"
);
}
case
"android/os/Build$VERSION->SDK:Ljava/lang/String;"
:{
return
new
StringObject(vm,
"29"
);
}
}
return
super
.getStaticObjectField(vm, dvmClass, signature);
}
JNIEnv
-
>NewStringUTF(
"Mrh0zeSVubXq3dRfAYRfsCpaeTaMt3WWlTMcCqCJesCJkrzjf63idS/q+MLRC/eIzbfdAP1pjrnI6gAiyORoTUHM1VLCpYGCeXjI6sIMuUQCAIaVpAfVen5tvqy2nIB+UqbivsbOBPYzY/QpsZ6oooAQE5SKp9J/rt2aNzSW6wErEQP8ey4EpRNoYyQjNguKY8FEtcOIaI5hEq5u2gwpl9YlKE8Wey3/JipF4+69Ez7ik1DVmaozl4j3wpjtgLo7fJRN/oZFPfAh8BwL2woSL/1yR5RakfRHtBLg28lUMTSOMwnGk2dPBTC7tZVsKho+CHx5NfZyHjW8L9PcxHQXpRZXOHH3ygB5/Q/2xrpm2J3l6bnqJ1xwGzubiqmvcD38fkBa+t44sNZ1mInNYkX82POjMKRnRXOth93zMQtSu8/7q7ya/dtfWQKFXFLuca5jr+UshG+EqsT9LeitqOxwJSv8UIeYZexsvsjXWBfamD7Noily5wVZF8nTOfwHMZe8H"
) was called
from
RX@
0x12026a34
[libencrypt.so]
0x26a34
结果
-
>Mrh0zeSVubXq3dRfAYRfsCpaeTaMt3WWlTMcCqCJesCJkrzjf63idS
/
q
+
MLRC
/
eIzbfdAP1pjrnI6gAiyORoTUHM1VLCpYGCeXjI6sIMuUQCAIaVpAfVen5tvqy2nIB
+
UqbivsbOBPYzY
/
QpsZ6oooAQE5SKp9J
/
rt2aNzSW6wErEQP8ey4EpRNoYyQjNguKY8FEtcOIaI5hEq5u2gwpl9YlKE8Wey3
/
JipF4
+
69Ez7ik1DVmaozl4j3wpjtgLo7fJRN
/
oZFPfAh8BwL2woSL
/
1yR5RakfRHtBLg28lUMTSOMwnGk2dPBTC7tZVsKho
+
CHx5NfZyHjW8L9PcxHQXpRZXOHH3ygB5
/
Q
/
2xrpm2J3l6bnqJ1xwGzubiqmvcD38fkBa
+
t44sNZ1mInNYkX82POjMKRnRXOth93zMQtSu8
/
7q7ya
/
dtfWQKFXFLuca5jr
+
UshG
+
EqsT9LeitqOxwJSv8UIeYZexsvsjXWBfamD7Noily5wVZF8nTOfwHMZe8H
JNIEnv
-
>NewStringUTF(
"Mrh0zeSVubXq3dRfAYRfsCpaeTaMt3WWlTMcCqCJesCJkrzjf63idS/q+MLRC/eIzbfdAP1pjrnI6gAiyORoTUHM1VLCpYGCeXjI6sIMuUQCAIaVpAfVen5tvqy2nIB+UqbivsbOBPYzY/QpsZ6oooAQE5SKp9J/rt2aNzSW6wErEQP8ey4EpRNoYyQjNguKY8FEtcOIaI5hEq5u2gwpl9YlKE8Wey3/JipF4+69Ez7ik1DVmaozl4j3wpjtgLo7fJRN/