首页
社区
课程
招聘
[原创]libkwsgmain.so Sig64 位
发表于: 2025-8-12 23:18 1265

[原创]libkwsgmain.so Sig64 位

2025-8-12 23:18
1265

在开始这篇文章之前,请阅读一下注意事项本文章仅用于学习研究,如有侵犯贵司权益,请联系告知,会立即做出下架删除处理。本文章不针对任何网站,APP ,禁止用于商业,转载,违法等用途。观看则默认同意本约定,未经允许禁止任何形式的转载,保留追究法律责任的权利,


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package com;
 
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Unicorn2Factory;
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.memory.Memory;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import com.github.unidbg.virtualmodule.android.JniGraphics;
import com.github.unidbg.virtualmodule.android.MediaNdkModule;
import com.github.unidbg.virtualmodule.android.SystemProperties;
 
import java.io.File;
import java.util.ArrayList;
import java.util.List;
 
 
public class 模板 extends AbstractJni implements IOResolver {
 
        private static final String PackName = "APP 包名";
        private static final String AppPath = "传入 APP路径";
        private static final String[] SoName = {"SO名字或外部路径"}; // 可能会出现多个SO文件加载的情况
        private final AndroidEmulator emulator;
        private final VM vm;
        private final Module module;
        final Memory memory;
 
 
        @Override
        public FileResult resolve(Emulator emulator, String pathname, int oflags) {
                System.out.println("Load File: " + pathname);
                return null;
        }
 
        private static LibraryResolver createLibraryResolver() {
                return new AndroidResolver(23);
        }
 
        private static AndroidEmulator createARMEmulator() {
                return AndroidEmulatorBuilder.for64Bit()
                .setProcessName(PackName)
                .addBackendFactory(new Unicorn2Factory(false))
                .build();
        }
 
        模板 () {
                emulator = createARMEmulator();
                // 创建模拟器的内存映射
                emulator.getSyscallHandler().addIOResolver(this);
                // 获取模拟器的内存操作接口
                memory = emulator.getMemory();
                // 设置系统类库解析 23
                memory.setLibraryResolver(createLibraryResolver());
                // 创建Android虚拟机,传入APK,Unidbg可以替我们做部分签名校验的工作
                vm = emulator.createDalvikVM(new File(AppPath));
                // 虚拟模块部分
                new AndroidModule(emulator,vm).register(memory);
                new MediaNdkModule(emulator,vm).register(memory);
                new JniGraphics(emulator,vm).register(memory);
                // 设置JNI
                vm.setJni(this);
                // 打印日志
                vm.setVerbose(true);
                // 加载目标SO
                DalvikModule dm = vm.loadLibrary(SoName[0], true);
                //获取本SO模块的句柄,后续需要用它
                module = dm.getModule();
                // 调用JNI OnLoad
                dm.callJNI_OnLoad(emulator);
        };
 
        public static void main(String[] args) {
                模板 action = new 模板();
                action.Call();
        }
 
        public void Call_64() {
                List<Object> list = new ArrayList<>(10);
                list.add(vm.getJNIEnv()); // 第⼀个参数是env
                DvmObject<?> thiz = vm.resolveClass("com/kuaishou/android/security/internal/dispatch/JNICLibrary").newObject(null);
                list.add(vm.addLocalObject(thiz)); // 第⼆个参数,实例⽅法是jobject,静态⽅法是jclass,直接填0,⼀般⽤不到。
                DvmObject<?> context = vm.resolveClass("com/yxcorp/gifshow/App").newObject(null); // context
                list.add(10418); //参数1
                StringObject urlObj = new StringObject(vm, "123456");
                ArrayObject arrayObject = new ArrayObject(urlObj);
                StringObject appkey = new StringObject(vm, "d7b7d042-d4f2-4012-be60-d97ff2429c17");
                DvmInteger intergetobj = DvmInteger.valueOf(vm, -1);
                DvmBoolean boolobj = DvmBoolean.valueOf(vm, false);
                DvmBoolean boolobj1 = DvmBoolean.valueOf(vm, true);
                StringObject appkey2 = new StringObject(vm, "7e46b28a-8c93-4940-8238-4c60e64e3c81");
                list.add(vm.addLocalObject(new ArrayObject(arrayObject, appkey, intergetobj, boolobj, context, DvmInteger.valueOf(vm, 0),boolobj1, appkey2)));
                Number numbers = module.callFunction(emulator, 0x40cd4, list.toArray());
                System.out.println("numbers:" + numbers);
                DvmObject<?> object = vm.getObject(numbers.intValue());
                String result = (String) object.getValue();
                System.out.println("result:" + result);
        }
 
}

逻辑分析

:::warning
该 算法 实际上 就是之前 提过的, 家族系的算法,但是也有可以学习的地方,例如说,分析大 Trace 多混淆指令下的 算法 应该如何分析,该案例 Trace 出来的日志 明显就是大于 之前讲过的 Sig3 大约是在 50 万行日志左右,那么我觉得可能是会对一个 阶梯式的学习研究是比较友好的案例

:::

这里呢 是固定了时间戳了的,如果不去固定时间戳的话,大家可以看看,和 Sig3 是非常类似的,因为 都是会受时间戳影响 导致最终密文结果的变化 , 那么就不再多赘述了。稍后会在分析完第一段的时候 再去详细讲一讲的。 下面开始分析的正文


第一轮的简单异或

首先 拿到 密文结果的时候, 先不要着急 直接开始追值,因为很多东西 去寻找的话 是很没有头绪的,尤其是对于该算法,日志较多,混淆也较多的情况下,那么应该是 先多计算几次 得出 不同的密文值 ,下面就是我自己计算出来的 两端密文值,可以简单先看看

1
2
3
5a54ebcd594b0dae efdfb998df714fbba08fa196e7d1e23056e324e090e6bfa4  // 第一次加密结果 密文123456
5a54ebcd594b0dae d7e781a0e749778398b799ae4111ef236edb1cd8a8de879c  // 第二次加密结果 密文随便填的
5a54ebcd594b0dae e4d4b2934e3eeec5ab84aa9decdae93b31e82feb9bedb4af  // 第二次加密结果 修改了时间戳 密文123456

那么 其实还是非常明显的,前面 16 位 都是固定的字符串,那么就可以直接关注后面那一段东西是怎么计算出来的了 例如说 简单的先搜一个 0xef

全文搜索 0xef

直接把 Trace 的日志 从搜索出来的结果 最后一条 往前面分析,很清晰的 有一条 EOR 的日志记录,看是 0x66 ^ 0x 89 => 0xef 那么 就果断判断 这就日志 是我们首先第一怀疑的日志点,这个是毫无疑问的,为什么,本来 Trace 日志就不太好分析,那么对 一些 Eor Add Ldrb... 就应该多一些敏感

直接开始检索 这段 指令的调用次数

全局检索 0x012658

实际上 结果还是异常的明显的, 记住这条指令, 还记得我们之前分析 Sig3 用到的手段吗? 控制变量的情况下, 多去 Trace 出来两份日志, 一般我就是喜欢三份日志 留两份日志做对比使用, 在这里,去检索其他两份日志的情况下 还是这条指令,其实呢就能发现,w12 是固定的表,那么 就可以直接简单的还原第一次的简单异或了

第一轮简单异或

:::success
实际上呢 这部分的内容 是最简单的点,因为我觉得 只要是有在前面的文章中 学习到方法和 搜索的思路的话,直接很快解决这个位置是很快的

:::


第二轮的简单异或

在文章的开头 我们就已经强调过,该系列的算法 有比较强的 **家族系的基因 **存在,那么大家看看,w11_before 这个值,24 个字节,难道不和我们之前讲过的 Sig3 是很相似的吗?那么实际上 后面就很好找到算法的位置了,例如直接 搜一些关键的值怎么组成的,0x89 可以搜 ff989

关键的位置

那么 后续 实际上 一些思路啊 和方法 都是一模一样的,大家可以借助 之前文章的解决思路和办法,再去实际体验一下 比较大 Trace 日志的追踪难度和追踪技巧,那么很多都是相同的点,我就不再多赘述了。

末尾

后续 也会推出一系列的文章,包括但不限于 魔改算法,VMP 系列,小众算法

欢迎加 V, 会给大家拉一个交流群 互相交流一下思路


传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 59
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
666
2025-8-13 17:31
0
雪    币: 155
活跃值: (240)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
大佬研究过10400这个参吗,返回的一直是0,10418的调用就没问题
2025-8-14 22:36
0
雪    币: 32
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
mb_ykavguun 大佬研究过10400这个参吗,返回的一直是0,10418的调用就没问题

看广告是玄学的 得你自己研究一下

最后于 2025-8-15 00:51 被沈聽白编辑 ,原因:
2025-8-15 00:51
0
雪    币: 222
活跃值: (1316)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
请问大佬知道unidbg初始化10412的时候,一直报错是怎么回事吗? 谢谢大佬
handleInterrupt intno=2, NR=160, svcNumber=0x1ed, PC=unidbg@0xfffe1704[libandroid.so]0x704, LR=RX@0x40037350[libkwsgmain.so]0x37350, syscall=null
2025-8-15 14:44
0
游客
登录 | 注册 方可回帖
返回