首页
社区
课程
招聘
[原创]2023腾讯游戏安全大赛-安卓赛道初赛wp
发表于: 2023-4-17 19:46 33782

[原创]2023腾讯游戏安全大赛-安卓赛道初赛wp

2023-4-17 19:46
33782

本文档是进行完相关分析之后的总结回忆, 所以可能有的地方的花指令是被去除了再截图的, 函数名和数据结构被重命名了. vm算法没有逆出来

根据题目提示要求, flag会在1000分的时候出现. 打开安装包发现是unity打包的游戏, 用010editor打开global-metadata.dat文件发现头文件没有被加密, 字符串也完好, 拖入il2cppdumper提示失败. ida打开libil2cpp.so查看init.array段, 第一个函数中看到了module_base: %p, g_unpacker: %p字符串, off_13BAFF0则是g_sec2023_p_array, 猜测是动态加载的时候会被libsec2023.so解密出来.

粗略看了一下解密挺复杂的, 所以首先尝试从内存中dump出来libil2cpp.so, 然后再使用il2cppdumper生成类信息, 这次可以直接成功. 观察数据结构类名函数名等信息, 在相关排查后确定老鼠的相关控制逻辑在MouseController类中, 其中有一个private void CollectCoin(Collider2D coinCollider)函数, 参数是碰撞器, 使用ida打开这个函数并且导入结构体类名信息, 其伪代码中出现了一个特殊的数字1000, 题目提到了分数多于1000即会出现flag, 估计关键点在这里.

​ 其关键位置原本的汇编指令是CMP W0, #0x3E8, 这里使用gg修改器修改为CMP W0, #0, 然后随便吃个金币后成功得到flag.

​ 前面分析大概能够猜测到libsec2023.so中大概率会存在反调试的功能, 首先在手机端开启frida_server, 结果并没有附加到游戏上打开游戏便被检测到了. 首先对其字符串操作函数进行hook看看有没有关键信息, hook掉strcmp, strncmp, strlen函数能够发现存在字符串re.frida.server的对比, 以及sscanf函数对maps文件的处理.

因为我并没有注入游戏就被检测了, 那么关于这种检测常见的有:

检测/data/local/tmp文件夹下的re.frida.server

检测27042端口

检测dbus

​ 查阅资料发现解决第一个问题需要重新编译frida, 这有点太麻烦了, 所以我直接打开frida_server的二进制文件patch掉re.frida.server字符串, 并且使用./fs -l 0.0.0.0:23948命令切换监听端口, 这样一来就能够成功过掉检测.

​ 在这之后我继续分析libil2cpp.so内的功能流程, 我发现frida hook它是没问题的, 但是只要hook libsec2023.so就会崩掉, 刚开始我是怀疑crc检测, 检测到了就调用kill或者exit等函数, 但是我hook掉退出函数发现并没有被调用. 对于这些检测函数, 其大概的逻辑是新开一个线程不间断扫描内存段, 并且计算出一个值, 如果值改变了那么就说明程序段被篡改了.

​ 针对上面这个逻辑, 我首先想到了frida的异常hook, 对指定的地址修改内存属性为只能执行, 读取后进入异常打印堆栈信息. 结果发现要么崩溃要么没有效果, 所以只能另外想办法.

​ 我这边正好有一个修改完内核之后的手机, 可以使用rwProcMem33开源项目中的硬件断点, 所以我使用这个工具尝试一下能否找到关键点. 结果成功定位到crc的关键函数, 下图中的libsec2023.so的基址是0x7d02bc8000

​ 命中地址0x7d02bff704减去基址得到偏移为0x37704, 为了保险还对其他的函数下了相同的内存断点, 发现断下来的地址只有这一个, 并且如果游戏进程没有重开, 返回值都相同, 跟进ida中查看是一个很简单的计算函数, 他的调用者sub_370AC很有可能就是进行相关操作的检测函数, 对其进行分析:

​ 因为前面分析知道sub_376CC正常情况的返回值都是相等的, 所以我们进行inlinehook之后会导致该返回值修改, 走到崩溃路线, 因此关键在cmp语句或者下面的cesl语句, 这句csel语句的意思是x8 = w0==w8 ? x8 : x9, x8与x9相差0x10, 这就导致了控制流的改变. 值得指出的是371F0这里的语句是错误的, 在内存dump下来的libsec2023.so中这里的值是BR X8. 将371DC处的值改为NOP之后x8的值就不会被修改为x9了, 也就绕过了inlinehook检测. 至此frida就能够完全正常使用了

​ 除了上面说到的反调试, 在libsec2023.so中还存在大量的花指令为csel...br reg形式的指令, 能够使得函数不被ida正常解析出来, 其br之后实际还是继续执行下一条指令. 在这些花指令中还藏着正常的选择语句块, 或者跳过几条语句的埋坑, 所以不方便用脚本批量还原掉, 我是踩完坑被误导之后才决定分析到哪里再配合frida-trace手动去除的.

​ 例如下面两个截图是还原前后的效果

​ 分析算法首先需要找到输入的值是从哪里传入的, 观察类名发现有一个SmallKeyboard类, 其中有被混淆过的参数, 经过一个个查看发现iI1Ii函数存在关键逻辑, 主要是有三种按键: 数字, 删除, 回车确定. 查看伪代码能够发现关键逻辑, 使用frida hook System_Convert__ToUInt64_8763844 得到其返回值确实就是我们的输入值. 为了方便, 我输入的值是666666, 对应的16进制值是0xa2c2a

​ 跟进SmallKeyboard__iI1Ii_4610736函数发现其最后jumpout到别的地方去了, 用frida hook后得到其跳转的位置是libsec2023.so + 0x31164处, 从这里开始有比较误导性的混淆, 我的截图都是去除混淆之后加了注释的.

sub_31164函数调用了sub_3B8CC之后拿到一个函数指针跳转出去了, 经过动态调试能够知道跳转到il2cpp中去了. 这里跟进看看sub_3B8CC做了什么事情.

​ 经过验证这个函数存在错误的b跳转, 伪代码因此是存在错误的, 按照截图中最后的返回值恒为0, 这显然是错误的. 但是可以看出来大概做了什么事情:

sub_3B9D4处理输入值

sub_3A924处理第一步输出值的一部分

sub_3A924处理第一步输出值的另一部分

返回

​ sub_3B9D4函数看起来很简单, 按照伪代码的逻辑, 对于输入值0, 我们应该返回(0x85-24)<<24, 也就是0x6d000000, 但最后的结果是0x6d94cae4. 那这个伪代码就没用了, 需要查看汇编代码是什么情况, 为了方便分析, 使用frida-trace对该函数进行一遍trace得到对应的log记录, 进行汇编分析, 汇编分析时以输入参数为发力点, 观察数据变化.

​ 分析完以上的汇编代码后可以还原对应的算法

​ 使用frida hook来验证结果是否正确, 确实无误

​ 之后来编写对应的逆算法为

​ 在这个函数中有很多复杂且奇怪的函数, 并且也出现了函数指针+1000多的数字, 因此可以猜想这里主要做的事情是准备java层环境, 之后调用java函数, 将伪代码中JNIEnv*参数类型标注出来. 刷新伪代码后能够很明显看到先new了一个java层的bytearray, 然后findclass, GetStaticMethodID得到函数, 最后在sub_3ABBC中调用这个函数.

​ 这里我首先对findclass进行hook, 发现类名是空的, 静态函数名称能得到是encrypt, 基本可以确定无误. 用jadx打开dex发现并没有这个函数, 因此怀疑是走RegisterNatives动态注册的. 使用frida对RegisterNatives进行hook, 发现了一条记录

​ 但是经过排查很明显不是上面的encrypt函数. 思考一下, 除了动态注册以外, 有可能是动态加载了dex, 于是使用frida-dexdump将内存中的dex dump下来. 果然在某个dex中发现了该函数.

​ 但是其控制流也被混淆了, 好在函数本身并不复杂, 因此可以将伪代码直接复制新建一个java工程, 测试功能完好之后对其进行调试分析, 将函数逻辑梳理一下得到其逻辑代码如下

​ 经过分析也能得出对应的逆算法为如下

​ 使用frida hook得到的结果与上面算法计算得到的结果一致

​ 梳理完这个函数那么算法在libsec2023.so的部分就已经结束了, 按照动态流程分析执行完sub_31164后会跳回到libil2cpp.so + 0x465AB4中, 从java层这个encrypt返回的结果与0x465AB4所拦截的结果是一致的. 所以libsec2023.so部分到此结束.

​ 这个函数是从libsec2023.so返回所进入的函数, 首先根据伪代码观察其流程, 主要做的事情是初始化了一些数组和对象, 将上一个encrypt的结果传入sub_46AD44函数中进行加密, 然后在一个do_while循环中进行第二次加密. 最后如果v28等于0并且v27与token的值相等就开启mod成功, 这里手动patch判断语句可以实现作弊功能, 所以整体思路是对的.

​ 首先来分析第一个sub_46AD44函数, 这个函数非常复杂, 主要是重要的字段名信息还有函数名信息都被混淆掉了.

​ 整个类中做了什么事情, 首先会初始化一些参数, 最重要的是某个迭代值(类内偏移0x2c), action词典(类内偏移0x38), 码表(类内偏移0x10). 该类在初始化的时候会注册0x1-0x16的值与某个操作函数对应关系在action词典中, 然后在一个大循环中随着迭代值的变化在码表中选择不同的action, 类似于状态机的实现. 下面这个sub_46AD44函数内的循环即是主要逻辑.

​ 最重要的事情是无论输入值是多少, 该状态机的码表和操作序列是一样的. 因此可以dump码表和操作序列, dump出来的码表和操作序列如下

​ 其中修改data的函数总共执行了48次, 且看起来非常有规律性, 因此一种可行方案是对这里用到的总共13种操作函数进行重写, 实现一个和游戏分离离线的状态机, 然后再对该算法进行逆向. 时间和工作量原因我这里并没有对该算法实现相应的逆向.

​ 虽然上一个算法并没有实现对应的逆向算法, 但是其输入输出是一一对应的, 所以这个部分也能够继续进行. 这个算法大部分数据的来源都是已知的, 除了其中的某个数组, 这个数组可以用frida获取, 并且其值是锁定的, 不会改变

​ v29本身的+8是跳过其他结构, 到数据区, 可以看到数组的下标一定是[0, 1, 2, 3]中的一个, 所以把数组的这四项dump下来即可实现该算法. 经过研究其等价的c代码如下:

​ 那么它的逆算法也能给出是这样的, 经过验算无误

​ 到此为止成功获取了flag, 过掉反调试使得frida能够正常工作, 之后静态分析加动态调试还原了除vm的算法以外的其余算法.

 
 
 
 
 
 
 
 
 
 
 
 
.text:00000000000371C8 41 01 00 94                   BL              sub_376CC ;调用的计算函数
.text:00000000000371C8
.text:00000000000371CC C8 1A 40 B9                   LDR             W8, [X22,#0x18]
.text:00000000000371D0 09 07 80 52                   MOV             W9, #0x38 ; '8'
.text:00000000000371D4 1F 00 08 6B                   CMP             W0, W8 ;对返回值进行判断
.text:00000000000371D8 08 05 80 52                   MOV             W8, #0x28 ; '('
.text:00000000000371DC 08 01 89 9A                   CSEL            X8, X8, X9, EQ ;根据判断结果进行赋值
.text:00000000000371E0 A8 6A 68 F8                   LDR             X8, [X21,X8]
.text:00000000000371E4 09 3E 91 52 49 F8 A6 72       MOV             W9, #0x37C289F0
.text:00000000000371EC 08 01 09 8B                   ADD             X8, X8, X9
.text:00000000000371F0 01 00 00 14                   B               loc_371F4
.text:00000000000371C8 41 01 00 94                   BL              sub_376CC ;调用的计算函数
.text:00000000000371C8
.text:00000000000371CC C8 1A 40 B9                   LDR             W8, [X22,#0x18]
.text:00000000000371D0 09 07 80 52                   MOV             W9, #0x38 ; '8'
.text:00000000000371D4 1F 00 08 6B                   CMP             W0, W8 ;对返回值进行判断
.text:00000000000371D8 08 05 80 52                   MOV             W8, #0x28 ; '('
.text:00000000000371DC 08 01 89 9A                   CSEL            X8, X8, X9, EQ ;根据判断结果进行赋值
.text:00000000000371E0 A8 6A 68 F8                   LDR             X8, [X21,X8]
.text:00000000000371E4 09 3E 91 52 49 F8 A6 72       MOV             W9, #0x37C289F0
.text:00000000000371EC 08 01 09 8B                   ADD             X8, X8, X9
.text:00000000000371F0 01 00 00 14                   B               loc_371F4
 
 
 
 
 
 
 
 
 
3b9e4         csel x10, xzr, x9, lo ;          x10 = 0xa2c5a --> 0x0   (null)
3b9e8           adrp x9, #0x7d03375000 ;         x9 = 0x28 --> 0x7d03375000   (�fC���>)
3b9ec           add x9, x9, #0xc40 ;     x9 = 0x7d03375000 --> 0x7d03375c40   q3�|)
3b9f0           ldr x10, [x9, x10] ;     x10 = 0x0 --> 0x7c8f337108
3b9f4           mov w11, #0x78fc ;       x11 = 0xb400007bb22885a0 --> 0x78fc
3b9f8           movk w11, #0x7400, lsl #16 ;     x11 = 0x78fc --> 0x740078fc
3b9fc           add x10, x10, x11 ;      x10 = 0x7c8f337108 --> 0x7d0333ea04   (j)
3ba00           br x10 ;必定跳转
3ba04           mov w10, #3 ;    x10 = 0x7d0333ea04 --> 0x3
3ba08           mov w11, #0x18 ;         x11 = 0x740078fc --> 0x18
3ba0c           cmp x10, #0 ;    x10 = 0x3
3ba10           mov w12, #0x10 ;         x12 = 0x0 --> 0x10
3ba14           csel x11, x12, x11, ge ;         x11 = 0x18 --> 0x10
3ba18           ldr x11, [x9, x11] ;     x11 = 0x10 --> 0x7c8f337138
3ba1c           mov w12, #0x78fc ;       x12 = 0x10 --> 0x78fc
3ba20           movk w12, #0x7400, lsl #16 ;     x12 = 0x78fc --> 0x740078fc
3ba24           str wzr, [sp, #0xc] ;    str = 0
3ba28           add x12, x11, x12 ;      x12 = 0x740078fc --> 0x7d0333ea34   (xh��3)
3ba2c           mov w11, #0x18 ;         x11 = 0x7c8f337138 --> 0x18
3ba30           br x12 ;必定跳转
;我称前面是第一个代码块
3ba34           ldr w12, [x0, x8, lsl #2] ;      x12 = 0x7d0333ea34 --> 0x0   (null)取参数值, 也就是高32位, 即0
3ba38           add x13, sp, #0xc ;      x13 = 0x6430bee2 --> 0x7cfe68653c
3ba3c           mov w14, #0x18 ;         x14 = 0x14da99d881a188 --> 0x18 从高到低选择字节
3ba40           lsr w12, w12, w11 ; 取字节
3ba44           eor w12, w12, w10 ;      x12 = 0x0 --> 0x3 和字节序号做异或
3ba48           strb w12, [x13, x10] ; 存到[sp, #0xc]的位置去, 此时顺序还是原来
...
;我称这为第二个代码块, 主要做的事情是取666666(64位)的高32位, 和字节序号异或存回去, 省略掉的部分是其他字节相同操作
3ba74           ldrb w11, [sp, #0xf] ;   x11 = 0xfffffff8 --> 0x3 第4字节
3ba78           ldrb w13, [sp, #0xd] ;   x13 = 0x740078fc --> 0x1 第2字节
3ba7c           mov w12, #0x86 ;         x12 = 0x7d0333ea74 --> 0x86
3ba80           ldrb w14, [sp, #0xe] ;   x14 = 0x18 --> 0x2 第3字节
3ba84           eor w11, w11, w12 ;      x11 = 0x3 --> 0x85 byte 40x86异或
3ba88           mov w12, #0xd3 ;         x12 = 0x86 --> 0xd3
3ba8c           eor w12, w13, w12 ;      x12 = 0xd3 --> 0xd2 0xd3和byte 2异或
3ba90           ldrb w13, [sp, #0xc] ;   x13 = 0x1 --> 0x0   (null) 第1字节
3ba94           strb w11, [sp, #0xf] ; 也就是最高字节和0x86异或存回去 byte[3] ^= 0x86
3ba98           sub w11, w14, #0x5e ;    x11 = 0x85 --> 0xffffffa4
3ba9c           strb w11, [sp, #0xe] ; byte[2] -= 0x5e
3baa0           mov w11, #3 ;    x11 = 0xffffffa4 --> 0x3
3baa4           sub w13, w13, #0x1c ;    x13 = 0x0 --> 0xffffffe4
3baa8           strb w12, [sp, #0xd] ; byte[1] ^= 0xd3
3baac           mov w12, #8 ;    x12 = 0xd2 --> 0x8
3bab0           strb w13, [sp, #0xc] ; byte[0] -= 0x1c 最低字节-0x1c存回去
3bab4           mov w13, #0x20 ;         x13 = 0xffffffe4 --> 0x20
3bab8           cmp x11, #0 ;    x11 = 0x3
3babc           str wzr, [x0, x8, lsl #2] ;      str = 0
3bac0           csel x12, x13, x12, ge ;         x12 = 0x8 --> 0x20
3bac4           ldr x12, [x9, x12] ;     x12 = 0x20 --> 0x7c8f3371e4
3bac8           mov w13, #0x78fc ;       x13 = 0x20 --> 0x78fc
3bacc           movk w13, #0x7400, lsl #16 ;     x13 = 0x78fc --> 0x740078fc
3bad0           mov w10, wzr ;   x10 = 0xffffffffffffffff --> 0x0   (null)
3bad4           add x13, x12, x13 ;      x13 = 0x740078fc --> 0x7d0333eae0   (�3)
3bad8           mov w12, #0x18 ;         x12 = 0x7c8f3371e4 --> 0x18
3badc           br x13 ;
;我称这为第三个代码块, 主要做的事情是每个字节分别进行对应加减法
3bae0           add x13, sp, #0xc ;      x13 = 0x7d0333eae0 --> 0x7cfe68653c   (�Ҥ�)
3bae4           ldrb w14, [x13, x11] ;   x14 = 0x2 --> 0x85 取最高字节
3bae8           sub w14, w14, w12 ;      x14 = 0x85 --> 0x6d
3baec           strb w14, [x13, x11] ;最高字节-0x18存回去 byte[3] -= 0x18
3baf0           and w14, w14, #0xff ;
3baf4           lsl w14, w14, w12 ;      x14 = 0x6d --> 0x6d000000
3baf8           sub x11, x11, #1 ;       x11 = 0x3 --> 0x2
3bafc           mov w13, #8 ;    x13 = 0x7cfe68653c --> 0x8
3bb00           add w10, w14, w10 ;      x10 = 0x0 --> 0x6d000000
3bb04           mov w14, #0x20 ;         x14 = 0x6d000000 --> 0x20
3bb08           cmp x11, #0 ;    x11 = 0x2
3bb0c           str w10, [x0, x8, lsl #2] ;      str = 0x6d000000 *result = byte[3]<<24
3bb10           csel x13, x14, x13, ge ;         x13 = 0x8 --> 0x20
3bb14           ldr x13, [x9, x13] ;     x13 = 0x20 --> 0x7c8f3371e4
3bb18           mov w14, #0x78fc ;       x14 = 0x20 --> 0x78fc
3bb1c           movk w14, #0x7400, lsl #16 ;     x14 = 0x78fc --> 0x740078fc
3bb20           sub w12, w12, #8 ;       x12 = 0x18 --> 0x10
3bb24           add x13, x13, x14 ;      x13 = 0x7c8f3371e4 --> 0x7d0333eae0   (�3)
3bb28           br x13 ;循环节
...
;我称这为第四个代码块, 主要做的事情是对每个字节分别进行byte[i] -= 8*i;
;在这之后代码会取低32位进行相同的操作
3b9e4         csel x10, xzr, x9, lo ;          x10 = 0xa2c5a --> 0x0   (null)
3b9e8           adrp x9, #0x7d03375000 ;         x9 = 0x28 --> 0x7d03375000   (�fC���>)
3b9ec           add x9, x9, #0xc40 ;     x9 = 0x7d03375000 --> 0x7d03375c40   q3�|)
3b9f0           ldr x10, [x9, x10] ;     x10 = 0x0 --> 0x7c8f337108
3b9f4           mov w11, #0x78fc ;       x11 = 0xb400007bb22885a0 --> 0x78fc
3b9f8           movk w11, #0x7400, lsl #16 ;     x11 = 0x78fc --> 0x740078fc
3b9fc           add x10, x10, x11 ;      x10 = 0x7c8f337108 --> 0x7d0333ea04   (j)
3ba00           br x10 ;必定跳转
3ba04           mov w10, #3 ;    x10 = 0x7d0333ea04 --> 0x3
3ba08           mov w11, #0x18 ;         x11 = 0x740078fc --> 0x18
3ba0c           cmp x10, #0 ;    x10 = 0x3
3ba10           mov w12, #0x10 ;         x12 = 0x0 --> 0x10
3ba14           csel x11, x12, x11, ge ;         x11 = 0x18 --> 0x10
3ba18           ldr x11, [x9, x11] ;     x11 = 0x10 --> 0x7c8f337138
3ba1c           mov w12, #0x78fc ;       x12 = 0x10 --> 0x78fc
3ba20           movk w12, #0x7400, lsl #16 ;     x12 = 0x78fc --> 0x740078fc
3ba24           str wzr, [sp, #0xc] ;    str = 0
3ba28           add x12, x11, x12 ;      x12 = 0x740078fc --> 0x7d0333ea34   (xh��3)
3ba2c           mov w11, #0x18 ;         x11 = 0x7c8f337138 --> 0x18
3ba30           br x12 ;必定跳转
;我称前面是第一个代码块
3ba34           ldr w12, [x0, x8, lsl #2] ;      x12 = 0x7d0333ea34 --> 0x0   (null)取参数值, 也就是高32位, 即0
3ba38           add x13, sp, #0xc ;      x13 = 0x6430bee2 --> 0x7cfe68653c
3ba3c           mov w14, #0x18 ;         x14 = 0x14da99d881a188 --> 0x18 从高到低选择字节
3ba40           lsr w12, w12, w11 ; 取字节
3ba44           eor w12, w12, w10 ;      x12 = 0x0 --> 0x3 和字节序号做异或
3ba48           strb w12, [x13, x10] ; 存到[sp, #0xc]的位置去, 此时顺序还是原来
...
;我称这为第二个代码块, 主要做的事情是取666666(64位)的高32位, 和字节序号异或存回去, 省略掉的部分是其他字节相同操作
3ba74           ldrb w11, [sp, #0xf] ;   x11 = 0xfffffff8 --> 0x3 第4字节
3ba78           ldrb w13, [sp, #0xd] ;   x13 = 0x740078fc --> 0x1 第2字节
3ba7c           mov w12, #0x86 ;         x12 = 0x7d0333ea74 --> 0x86
3ba80           ldrb w14, [sp, #0xe] ;   x14 = 0x18 --> 0x2 第3字节
3ba84           eor w11, w11, w12 ;      x11 = 0x3 --> 0x85 byte 40x86异或
3ba88           mov w12, #0xd3 ;         x12 = 0x86 --> 0xd3
3ba8c           eor w12, w13, w12 ;      x12 = 0xd3 --> 0xd2 0xd3和byte 2异或
3ba90           ldrb w13, [sp, #0xc] ;   x13 = 0x1 --> 0x0   (null) 第1字节
3ba94           strb w11, [sp, #0xf] ; 也就是最高字节和0x86异或存回去 byte[3] ^= 0x86
3ba98           sub w11, w14, #0x5e ;    x11 = 0x85 --> 0xffffffa4
3ba9c           strb w11, [sp, #0xe] ; byte[2] -= 0x5e
3baa0           mov w11, #3 ;    x11 = 0xffffffa4 --> 0x3
3baa4           sub w13, w13, #0x1c ;    x13 = 0x0 --> 0xffffffe4
3baa8           strb w12, [sp, #0xd] ; byte[1] ^= 0xd3
3baac           mov w12, #8 ;    x12 = 0xd2 --> 0x8
3bab0           strb w13, [sp, #0xc] ; byte[0] -= 0x1c 最低字节-0x1c存回去
3bab4           mov w13, #0x20 ;         x13 = 0xffffffe4 --> 0x20
3bab8           cmp x11, #0 ;    x11 = 0x3
3babc           str wzr, [x0, x8, lsl #2] ;      str = 0
3bac0           csel x12, x13, x12, ge ;         x12 = 0x8 --> 0x20
3bac4           ldr x12, [x9, x12] ;     x12 = 0x20 --> 0x7c8f3371e4
3bac8           mov w13, #0x78fc ;       x13 = 0x20 --> 0x78fc
3bacc           movk w13, #0x7400, lsl #16 ;     x13 = 0x78fc --> 0x740078fc
3bad0           mov w10, wzr ;   x10 = 0xffffffffffffffff --> 0x0   (null)
3bad4           add x13, x12, x13 ;      x13 = 0x740078fc --> 0x7d0333eae0   (�3)
3bad8           mov w12, #0x18 ;         x12 = 0x7c8f3371e4 --> 0x18
3badc           br x13 ;
;我称这为第三个代码块, 主要做的事情是每个字节分别进行对应加减法
3bae0           add x13, sp, #0xc ;      x13 = 0x7d0333eae0 --> 0x7cfe68653c   (�Ҥ�)
3bae4           ldrb w14, [x13, x11] ;   x14 = 0x2 --> 0x85 取最高字节
3bae8           sub w14, w14, w12 ;      x14 = 0x85 --> 0x6d
3baec           strb w14, [x13, x11] ;最高字节-0x18存回去 byte[3] -= 0x18
3baf0           and w14, w14, #0xff ;
3baf4           lsl w14, w14, w12 ;      x14 = 0x6d --> 0x6d000000
3baf8           sub x11, x11, #1 ;       x11 = 0x3 --> 0x2
3bafc           mov w13, #8 ;    x13 = 0x7cfe68653c --> 0x8
3bb00           add w10, w14, w10 ;      x10 = 0x0 --> 0x6d000000
3bb04           mov w14, #0x20 ;         x14 = 0x6d000000 --> 0x20
3bb08           cmp x11, #0 ;    x11 = 0x2
3bb0c           str w10, [x0, x8, lsl #2] ;      str = 0x6d000000 *result = byte[3]<<24
3bb10           csel x13, x14, x13, ge ;         x13 = 0x8 --> 0x20
3bb14           ldr x13, [x9, x13] ;     x13 = 0x20 --> 0x7c8f3371e4
3bb18           mov w14, #0x78fc ;       x14 = 0x20 --> 0x78fc
3bb1c           movk w14, #0x7400, lsl #16 ;     x14 = 0x78fc --> 0x740078fc
3bb20           sub w12, w12, #8 ;       x12 = 0x18 --> 0x10
3bb24           add x13, x13, x14 ;      x13 = 0x7c8f3371e4 --> 0x7d0333eae0   (�3)
3bb28           br x13 ;循环节
...

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-4-17 20:18 被juice4fun编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (2)
雪    币: 2428
活跃值: (10698)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
66666
2023-4-18 09:15
0
雪    币: 3525
活跃值: (31011)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
tql
2023-4-29 12:23
0
游客
登录 | 注册 方可回帖
返回
//