跟着龙哥学 SO逆向入门实战教程一:OASIS
前言
/*
# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
frida -UF -l Hook.js -o hook.log
call_java()
# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
function hook_java() {
Java.perform(function () {
var NativeApi = Java.use('com.weibo.xvideo.NativeApi');
// 使用系统工具类将byte数组转成hex、utf8.
var ByteString = Java.use("com.android.okhttp.okio.ByteString");
NativeApi.s.implementation = function (str1, str2) {
/* 这样也可以
var StringCls = Java.use("java.lang.String");
var stringVal = StringCls.$new(str1, "utf-8");
console.log("NativeApi s param:", stringVal, str2);
*/
var result = this.s(str1, str2);
console.log("NativeApi str:" + ByteString.of(str1).utf8())
// console.log("hex:" + ByteString.of(str1).hex())
console.log("NativeApi result:" + result);
return result;
}
});
}
function call_java() {
var securityUtil = null;
Java.perform(function () {
Java.choose("com.weibo.xvideo.NativeApi", {
//枚举时调用
onMatch: function (instance) {
//打印实例
securityUtil = instance;
console.log("find instance")
},
//枚举完成后调用
onComplete: function () {
console.log("end")
}
});
var javaString = Java.use('java.lang.String');
var str = "aid=01A5bEg1VpHUmdB92RsAS7tsf-wTU6Eg41MEUWUYgsMDG6rq8.&cfrom=28B5295010&cuid=7529403746&filter_quick_replay=0&filter_rainbow=0&noncestr=0x3pp5rIbBIH8R1U7h67o675rh7522&platform=ANDROID×tamp=1628603374728&ua=Xiaomi-Mi8__oasis__3.5.8__Android__Android8.1.0&version=3.5.8&vid=2004301948574&wm=20004_90024";
var input1 = javaString.$new(str).getBytes();
var result = securityUtil.s(input1, false);
console.log(result);
})
}
--------------------
com.sina.oasis 绿洲
start...
end...
--------------------
NativeApi str:aid=01A5bEg1VpHUmdB92RsAS7tsf-wTU6Eg41MEUWUYgsMDG6rq8.&cfrom=28B5295010&cuid=7529403746&filter_quick_replay=0&filter_rainbow=0&noncestr=0x3pp5rIbBIH8R1U7h67o675rh7522&platform=ANDROID×tamp=1628603374728&ua=Xiaomi-Mi8__oasis__3.5.8__Android__Android8.1.0&version=3.5.8&vid=2004301948574&wm=20004_90024
NativeApi result:fe93d8397edb90c4d84f2248370cb82a
--------------------
find instance
end
fe93d8397edb90c4d84f2248370cb82a
--------------------
[RegisterNatives] javaClass: com.weibo.xvideo.NativeApi name: s sig: ([BZ)Ljava/lang/String; fnPtr: 0x7d3d0696cc soName: liboasiscore.so soBase: 0x7d3d058000 funcOffset: 0x116cc
[RegisterNatives] javaClass: com.weibo.xvideo.NativeApi name: e sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7d3d069af4 soName: liboasiscore.so soBase: 0x7d3d058000 funcOffset: 0x11af4
[RegisterNatives] javaClass: com.weibo.xvideo.NativeApi name: d sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7d3d069cd8 soName: liboasiscore.so soBase: 0x7d3d058000 funcOffset: 0x11cd8
[RegisterNatives] javaClass: com.weibo.xvideo.NativeApi name: dg sig: (Ljava/lang/String;Z)Ljava/lang/String; fnPtr: 0x7d3d06a20c soName: liboasiscore.so soBase: 0x7d3d058000 funcOffset: 0x1220c
findHash (v0.1) plugin has been loaded.
这个脚本只考虑了32位SO的反编译代码,64位未适配。
adb install -r --abi armeabi-v7a E:\Download\1.apk
RegisterNative(com/weibo/xvideo/NativeApi, s([BZ)Ljava/lang/String;, RX@0x400116cc[liboasiscore.so]0x116cc)
RegisterNative(com/weibo/xvideo/NativeApi, e(Ljava/lang/String;)Ljava/lang/String;, RX@0x40011af4[liboasiscore.so]0x11af4)
RegisterNative(com/weibo/xvideo/NativeApi, d(Ljava/lang/String;)Ljava/lang/String;, RX@0x40011cd8[liboasiscore.so]0x11cd8)
RegisterNative(com/weibo/xvideo/NativeApi, dg(Ljava/lang/String;Z)Ljava/lang/String;, RX@0x4001220c[liboasiscore.so]0x1220c)
JNIEnv->GetArrayLength([B@b97c004 => 305) was called from RX@0x4001174c[liboasiscore.so]0x1174c
JNIEnv->NewStringUTF("fe93d8397edb90c4d84f2248370cb82a") was called from RX@0x4001191c[liboasiscore.so]0x1191c
fe93d8397edb90c4d84f2248370cb82a
package com.sina.oasis;
// 导入通用且标准的类库
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
// 继承AbstractJni类
public class oasis64 extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
private final Module module;
oasis64() {
// 创建模拟器实例,进程名建议依照实际进程名填写,可以规避针对进程名的校验
emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("com.sina.oasis").build();
// 获取模拟器的内存操作接口
final Memory memory = emulator.getMemory();
// 设置系统类库解析
memory.setLibraryResolver(new AndroidResolver(23));
// 创建Android虚拟机,传入APK,Unidbg可以替我们做部分签名校验的工作
vm = emulator.createDalvikVM(new File("unidbg-android/src/test/resources/com.sina.oasis/com.sina.oasis.apk"));
// 加载目标SO
DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/com.sina.oasis/arm64-v8a/liboasiscore.so"), true); // 加载so到虚拟内存
//获取本SO模块的句柄,后续需要用它
module = dm.getModule();
vm.setJni(this); // 设置JNI
vm.setVerbose(true); // 打印日志
dm.callJNI_OnLoad(emulator); // 调用JNI OnLoad
}
public static void main(String[] args) {
oasis64 test = new oasis64();
System.out.println(test.getS());
}
public String getS() {
// args list
List<Object> list = new ArrayList<>(10);
// arg1 env
list.add(vm.getJNIEnv());
// arg2 jobject/jclazz 一般用不到,直接填0
list.add(0);
// arg3 bytes
// result:fe93d8397edb90c4d84f2248370cb82a
String input = "aid=01A5bEg1VpHUmdB92RsAS7tsf-wTU6Eg41MEUWUYgsMDG6rq8." +
"&cfrom=28B5295010" +
"&cuid=7529403746" +
"&filter_quick_replay=0" +
"&filter_rainbow=0" +
"&noncestr=0x3pp5rIbBIH8R1U7h67o675rh7522" +
"&platform=ANDROID" +
"×tamp=1628603374728" +
"&ua=Xiaomi-Mi8__oasis__3.5.8__Android__Android8.1.0" +
"&version=3.5.8" +
"&vid=2004301948574" +
"&wm=20004_90024";
/* String input = "aid=01A-khBWIm48A079Pz_DMW6PyZR8" +
"uyTumcCNm4e8awxyC2ANU.&cfrom=28B529501" +
"0&cuid=5999578300&noncestr=46274W9279Hr1" +
"X49A5X058z7ZVz024&platform=ANDROID×tamp" +
"=1621437643609&ua=Xiaomi-MIX2S__oasis__3.5.8_" +
"_Android__Android10&version=3.5.8&vid=10190135" +
"94003&wm=20004_90024";*/
byte[] inputByte = input.getBytes(StandardCharsets.UTF_8);
ByteArray inputByteArray = new ByteArray(vm, inputByte);
list.add(vm.addLocalObject(inputByteArray));
// arg4 ,boolean false 填入0
list.add(0);
// 参数准备完成
// call function
Number number = module.callFunction(emulator, 0x116cc, list.toArray())[0];
String result = vm.getObject(number.intValue()).getValue().toString();
return result;
}
}
The initial autoanalysis has been finished.
findHash (v0.1) plugin has been loaded.
***************************在二进制文件中检索hash算法常量************************************
0x2a322:padding used in hashing algorithms (0x80 0 ... 0)
0x6131:函数sub_6130疑似哈希函数,包含初始化魔数的代码。
0x8975:函数sub_8974疑似哈希函数,包含初始化魔数的代码。
0x1225d:函数sub_1225C疑似哈希函数运算部分。
0x1935d:函数sub_1935C疑似哈希函数运算部分。
0x1f465:函数sub_1F464疑似哈希函数运算部分。
0x22091:函数sub_22090疑似哈希函数运算部分。
***************************存在以下可疑的字符串************************************
0x295e7:/Volumes/Android/buildbot/src/android/ndk-release-r17/external/libcxx/../../external/libcxxabi/src/abort_message.cpp
0x29b6c:/Volumes/Android/buildbot/src/android/ndk-release-r17/external/libcxx/../../external/libunwind_llvm/src/Unwind-EHABI.cpp
0x29cc8:/Volumes/Android/buildbot/src/android/ndk-release-r17/external/libcxx/../../external/libunwind_llvm/src/UnwindCursor.hpp
0x29d4d:/Volumes/Android/buildbot/src/android/ndk-release-r17/external/libcxx/../../external/libunwind_llvm/src/Registers.hpp
生成对应的hook脚本如下:
frida -UF -l C:\Users\zhoumi\Desktop\demo1\liboasiscore_findhash_1628655879.js
***********************************************************************************
花费 120.12736535072327 秒,因为会对全部函数反编译,所以比较耗时间哈
函数sub_8974疑似哈希函数,包含初始化魔数的代码。
0xc4e9a461 liboasiscore.so!0xc461
function hook_md5_update() {
var soAddr = Module.findBaseAddress("liboasiscore.so");
//thumb
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var relativePtr = 0x8AB2 + 1;
var funcPtr = soAddr.add(relativePtr);
Interceptor.attach(funcPtr, {
onEnter: function (args) {
// console.log("args onEnter args[0]: ", ptr(args[0])); // 内存 地址
console.log("args onEnter args[1]: \n", ptr(args[1]).readCString()); // 内存 地址
console.log("args onEnter args[1]: \n", hexdump(args[1], { length: args[2].toInt32() })); // 16 进制 ASCII码;
console.log("args onEnter args[2]: \n" + args[2].toInt32());
this.args0 = args[0];
},
onLeave: function (retval) {
// console.log("retval onLeave retval: ", (retval)); // 内存 地址
console.log("retval onLeave this.args0: \n", hexdump(this.args0, { length: 20 }));
}
});
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}
(fridaMi10) D:\Project\AndroidSecurity\FridaHook>frida -UF -l Hook.js -o hook.log
____
/ _ | Frida 14.2.18 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
--------------------
com.sina.oasis 绿洲
start...
end...
--------------------
[Mi 8::绿洲]-> call_java();
find instance
end
args onEnter args[1]:
YP1Vty&$Xm*kJkoR,Opk&aid=01A5bEg1VpHUmdB92RsAS7tsf-wTU6Eg41MEUWUYgsMDG6rq8.&cfrom=28B5295010&cuid=7529403746&filter_quick_replay=0&filter_rainbow=0&noncestr=0x3pp5rIbBIH8R1U7h67o675rh7522&platform=ANDROID×tamp=1628603374728&ua=Xiaomi-Mi8__oasis__3.5.8__Android__Android8.1.0&version=3.5.8&vid=2004301948574&wm=20004_90024
args onEnter args[1]:
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
ddba4a00 59 50 31 56 74 79 26 24 58 6d 2a 6b 4a 6b 6f 52 YP1Vty&$Xm*kJkoR
ddba4a10 2c 4f 70 6b 26 61 69 64 3d 30 31 41 35 62 45 67 ,Opk&aid=01A5bEg
ddba4a20 31 56 70 48 55 6d 64 42 39 32 52 73 41 53 37 74 1VpHUmdB92RsAS7t
ddba4a30 73 66 2d 77 54 55 36 45 67 34 31 4d 45 55 57 55 sf-wTU6Eg41MEUWU
ddba4a40 59 67 73 4d 44 47 36 72 71 38 2e 26 63 66 72 6f YgsMDG6rq8.&cfro
ddba4a50 6d 3d 32 38 42 35 32 39 35 30 31 30 26 63 75 69 m=28B5295010&cui
ddba4a60 64 3d 37 35 32 39 34 30 33 37 34 36 26 66 69 6c d=7529403746&fil
ddba4a70 74 65 72 5f 71 75 69 63 6b 5f 72 65 70 6c 61 79 ter_quick_replay
ddba4a80 3d 30 26 66 69 6c 74 65 72 5f 72 61 69 6e 62 6f =0&filter_rainbo
ddba4a90 77 3d 30 26 6e 6f 6e 63 65 73 74 72 3d 30 78 33 w=0&noncestr=0x3
ddba4aa0 70 70 35 72 49 62 42 49 48 38 52 31 55 37 68 36 pp5rIbBIH8R1U7h6
ddba4ab0 37 6f 36 37 35 72 68 37 35 32 32 26 70 6c 61 74 7o675rh7522&plat
ddba4ac0 66 6f 72 6d 3d 41 4e 44 52 4f 49 44 26 74 69 6d form=ANDROID&tim
ddba4ad0 65 73 74 61 6d 70 3d 31 36 32 38 36 30 33 33 37 estamp=162860337
ddba4ae0 34 37 32 38 26 75 61 3d 58 69 61 6f 6d 69 2d 4d 4728&ua=Xiaomi-M
ddba4af0 69 38 5f 5f 6f 61 73 69 73 5f 5f 33 2e 35 2e 38 i8__oasis__3.5.8
ddba4b00 5f 5f 41 6e 64 72 6f 69 64 5f 5f 41 6e 64 72 6f __Android__Andro
ddba4b10 69 64 38 2e 31 2e 30 26 76 65 72 73 69 6f 6e 3d id8.1.0&version=
ddba4b20 33 2e 35 2e 38 26 76 69 64 3d 32 30 30 34 33 30 3.5.8&vid=200430
ddba4b30 31 39 34 38 35 37 34 26 77 6d 3d 32 30 30 30 34 1948574&wm=20004
ddba4b40 5f 39 30 30 32 34 _90024
args onEnter args[2]:
326
retval onLeave this.args0:
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
bff0297c 00 00 00 00 9c 94 4e 9d db 99 fc d2 0c 71 30 68 ......N......q0h
bff0298c 19 e1 d2 03 ....
args onEnter args[1]:
�
args onEnter args[1]:
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
c4eb8322 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c4eb8332 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c4eb8342 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c4eb8352 00 00 ..
args onEnter args[2]:
50
retval onLeave this.args0:
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
bff0297c 00 00 00 00 9c 94 4e 9d db 99 fc d2 0c 71 30 68 ......N......q0h
bff0298c 19 e1 d2 03 ....
args onEnter args[1]:
0
args onEnter args[1]:
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
bff028f8 30 0a 00 00 00 00 00 00 0.......
args onEnter args[2]:
8
retval onLeave this.args0:
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
bff0297c 00 00 00 00 fe 93 d8 39 7e db 90 c4 d8 4f 22 48 .......9~....O"H
bff0298c 37 0c b8 2a 7..*
result fe93d8397edb90c4d84f2248370cb82a
MD5 Update一共被调用了三次,需要注意的是,MD5的Update的后两次调用,都是数据的填充,属于算法内部细节,所以我们只用关注第一次的输出。
我们的明文是从aid开始的,前面多了一块,这一块每次运行都不变,所以猜测它是盐,使用逆向之友Cyberchef 测试一下: