做字幕网站怎么建立一个公司的网站
版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/
目标 so 分析
目标方法反汇编视图如下
F5 反汇编代码如下,很明显通过 fla 隐藏了真实的执行流
__int64 __usercall dynamicBase64Encode@<X0>(const unsigned __int8 *a1@<X0>, unsigned __int64 a2@<X1>, __int64 a3@<X8>)
{int v3; // w8int v4; // w8unsigned __int8 *v5; // x0int v6; // w8unsigned __int8 *v7; // x0__int64 result; // x0int i; // [xsp+20h] [xbp-60h]unsigned __int64 v11; // [xsp+30h] [xbp-50h]int v12; // [xsp+3Ch] [xbp-44h]int v13; // [xsp+40h] [xbp-40h]char v16[24]; // [xsp+60h] [xbp-20h] BYREF__int64 v17; // [xsp+78h] [xbp-8h]v17 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);generateDynamicBase64Alphabet(a2);sub_29574(a3);v13 = 0;v12 = -6;v11 = 0LL;do{if ( v11 >= a2 )v3 = 491;elsev3 = 26962;for ( i = v3; ; i = 24464 ){while ( 1 ){while ( 1 ){while ( 1 ){while ( 1 ){while ( 1 ){while ( 1 ){while ( i == 491 ){if ( v12 <= -6 )v6 = 4827;elsev6 = 2995;i = v6;}if ( i != 2995 )break;v7 = (unsigned __int8 *)sub_2E280(v16, (v13 << 8 >> (v12 + 8)) & 0x3F);std::string::push_back(a3, *v7);i = 4827;}if ( i != 4827 )break;i = 32391;}if ( i != 5705 )break;v5 = (unsigned __int8 *)sub_2E280(v16, (v13 >> v12) & 0x3F);std::string::push_back(a3, *v5);v12 -= 6;i = 24464;}if ( i != 9961 )break;++v11;i = 29358;}if ( i != 16827 )break;i = 9961;}if ( i != 24464 )break;if ( v12 < 0 )v4 = 16827;elsev4 = 5705;i = v4;}if ( i != 26962 )break;v13 = a1[v11] | (v13 << 8);v12 += 8;}}while ( i == 29358 );result = std::string::~string(v16);_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));return result;
}
unidbg 中调用目标 so 函数
把 so 放到 resource 目录下
关于 unidbg 的详细介绍可以参考这篇文章:unidbg 加载 so 并调用 so 中函数
通过 unidbg 加载 so 并执行 so 中目标函数
package com.cyrus.example;import com.alibaba.fastjson.util.IOUtils;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.DvmObject;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.linux.android.dvm.jni.ProxyClassFactory;
import com.github.unidbg.memory.Memory;import java.io.File;public class TraceDemo {public static void main(String[] args) {TraceDemo demo = new TraceDemo();demo.run();demo.destroy();}private void destroy() {IOUtils.close(emulator);}private final AndroidEmulator emulator;private TraceDemo() {// 创建一个 64 位的 Android 模拟器实例emulator = AndroidEmulatorBuilder.for64Bit() // 设置为 64 位模拟.setProcessName("com.cyrus.example") // 进程名称.build(); // 创建模拟器实例// 获取模拟器的内存实例Memory memory = emulator.getMemory();// 创建一个库解析器,并设置 Android 版本为 23(Android 6.0)LibraryResolver resolver = new AndroidResolver(23);// 将库解析器设置到模拟器的内存中,确保加载库时能够解析符号memory.setLibraryResolver(resolver);}public void run() {// 创建一个 Dalvik 虚拟机实例VM vm = emulator.createDalvikVM();// 启用虚拟机的调试输出vm.setVerbose(true);vm.setDvmClassFactory(new ProxyClassFactory());// 加载 so 到 Dalvik 虚拟机中,并设置为需要自动初始化库DalvikModule module = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/cyrus/lib_ollvm_fla_base64.so"), true);// 调用 JNI_Onloadmodule.callJNI_OnLoad(emulator);// 注册 Base64Activity 类DvmClass dvmClass = vm.resolveClass("com/cyrus/example/base64/Base64Activity");// 创建 Java 对象DvmObject object = dvmClass.newObject(null);// 调用 jni 方法 dynamicBase64Encode 并传参 ByteArrayDvmObject result = object.callJniMethodObject(emulator, "dynamicBase64Encode([B)Ljava/lang/String;", "lskvIIF".getBytes());System.out.println("result:" + result);}
}
unidbg trace
在 callJniMethodObject 方法之前添加如下代码,trace 指令执行和内存读写,并把 trace log 输出到文件。
// 日志保存到文件
PrintStream fileOut;
try {// 获取当前时间,格式化为 yyyyMMdd_HHmmssString timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());String filename = "trace_log_" + timestamp + ".txt";fileOut = new PrintStream(new FileOutputStream(filename));
} catch (FileNotFoundException e) {throw new RuntimeException(e);
}
System.setOut(fileOut);
System.setErr(fileOut);// trace 指令
emulator.traceCode();
// trace 内存读取
emulator.traceRead();
// trace 内存写入
emulator.traceWrite();
得到 trace log,包含指令流、寄存器变化、内存读写信息
算法还原
根据真实的执行指令流去还原算法执行过程
#include <cstdint>
#include <cstdlib>
#include <string>
#include <cstring>alignas(16) const __int128 xmmword_14B00 = (__int128) 0x4000000000000000LL << 64 | 0x51; // 全局 128-bit 常量 xmmword_14B00
alignas(16) __int128 xmmword_54C30; // / 全局 128-bit 变量 xmmword_54C30
char *qword_54C40 = nullptr; // 存储 Base64 码表指针void sub_23F30() {// 分配 80 字节(0x50)内存char *v0 = new char[0x50];// 复制 xmmword_14B00 的内容到 xmmword_54C30xmmword_54C30 = xmmword_14B00;// 保存 Base64 码表地址qword_54C40 = v0;// 复制标准 Base64 码表到 v0strcpy(v0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
}std::string dynamicBase64Encode(const unsigned __int8 *a1, __int64 a2) {// 输出std::string a3;__int128 *v6; // x0__int128 v7; // q0__int64 v8; // x8char *v9; // x12__int64 v10; // x14char v11; // w12char *v12; // x11__int64 v13; // x26int v14; // w25int v15; // w8char *v16; // x27unsigned int v17; // w28int v18; // w8char *v19; // x9__int128 v20; // [xsp+0h] [xbp-20h] BYREFvoid *v21; // [xsp+10h] [xbp-10h]__int64 v22; // [xsp+18h] [xbp-8h]// 访问 CPU 状态信息// v22 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);v6 = (__int128 *) operator new(0x50uLL);*(__int64 *) &v7 = 0x2020202020202020LL;*((__int64 *) &v7 + 1) = 0x2020202020202020LL;v8 = 0LL;v21 = v6;*((uint8_t *) v6 + 64) = 0;*v6 = v7;v6[1] = v7;v6[2] = v7;v6[3] = v7;v20 = xmmword_14B00;do {v9 = (char *) qword_54C40;v10 = a2 & 0x3F ^ v8;if ((xmmword_54C30 & 1) == 0)v9 = (char *) &xmmword_54C30 + 1;v11 = v9[v8++];if ((v20 & 1) != 0)v12 = (char *) v21;elsev12 = (char *) &v20 + 1;v12[v10] = v11;} while (v8 != 64);// *a3 = 0LL;
// a3[1] = 0LL;
// a3[2] = 0LL;a3.clear(); // 清空字符串if (a2) {v13 = 0LL;v14 = 0;v15 = -6;if ((v20 & 1) != 0)v16 = (char *) v21;elsev16 = (char *) &v20 + 1;do {v14 = a1[v13] | (v14 << 8);if (v15 < -8) {v15 += 8;} else {v17 = v15 + 14;do {v17 -= 6;a3.push_back((unsigned __int8) v16[(v14 >> v17) & 0x3FLL]);} while (v17 > 5);v15 = v17 - 6;}++v13;} while (v13 != a2);if ((unsigned int) v15 > 0xFFFFFFFA) {v18 = v14 << 8 >> (v15 + 8);if ((v20 & 1) != 0)v19 = (char *) v21;elsev19 = (char *) &v20 + 1;a3.push_back((unsigned __int8) v19[v18 & 0x3E]);}}if ((v20 & 1) != 0)operator delete(v21);return a3;
}int main() {// 初始化全局变量sub_23F30();// 要编码的原始数据std::string input = "lskvIIF";// 调用 Base64 编码函数std::string result = dynamicBase64Encode(reinterpret_cast<const uint8_t*>(input.c_str()), input.size());printf("input: %s\n", input.c_str());printf("result: %s", result.c_str());return 0;
}
输出如下:
完整源码
package com.cyrus.example;import com.alibaba.fastjson.util.IOUtils;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.DvmObject;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.linux.android.dvm.jni.ProxyClassFactory;
import com.github.unidbg.memory.Memory;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;public class TraceDemo {public static void main(String[] args) {TraceDemo demo = new TraceDemo();demo.run();demo.destroy();}private void destroy() {IOUtils.close(emulator);}private final AndroidEmulator emulator;private TraceDemo() {// 创建一个 64 位的 Android 模拟器实例emulator = AndroidEmulatorBuilder.for64Bit() // 设置为 64 位模拟.setProcessName("com.cyrus.example") // 进程名称.build(); // 创建模拟器实例// 获取模拟器的内存实例Memory memory = emulator.getMemory();// 创建一个库解析器,并设置 Android 版本为 23(Android 6.0)LibraryResolver resolver = new AndroidResolver(23);// 将库解析器设置到模拟器的内存中,确保加载库时能够解析符号memory.setLibraryResolver(resolver);}public void run() {// 创建一个 Dalvik 虚拟机实例VM vm = emulator.createDalvikVM();// 启用虚拟机的调试输出vm.setVerbose(true);vm.setDvmClassFactory(new ProxyClassFactory());// 加载 so 到 Dalvik 虚拟机中,并设置为需要自动初始化库DalvikModule module = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/cyrus/lib_ollvm_fla_base64.so"), true);// 调用 JNI_Onloadmodule.callJNI_OnLoad(emulator);// 注册 Base64Activity 类DvmClass dvmClass = vm.resolveClass("com/cyrus/example/base64/Base64Activity");// 创建 Java 对象DvmObject object = dvmClass.newObject(null);// 日志保存到文件PrintStream fileOut;try {// 获取当前时间,格式化为 yyyyMMdd_HHmmssString timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());String filename = "trace_log_" + timestamp + ".txt";fileOut = new PrintStream(new FileOutputStream(filename));} catch (FileNotFoundException e) {throw new RuntimeException(e);}System.setOut(fileOut);System.setErr(fileOut);// trace 指令emulator.traceCode();// trace 内存读取emulator.traceRead();// trace 内存写入emulator.traceWrite();// 调用 jni 方法 dynamicBase64Encode 并传参 ByteArrayDvmObject result = object.callJniMethodObject(emulator, "dynamicBase64Encode([B)Ljava/lang/String;", "lskvIIF".getBytes());System.out.println("result:" + result);}}
完整源码地址:https://github.com/CYRUS-STUDIO/unidbg