某猿口算sign分析
本文最后更新于 549 天前,其中的信息可能已经有所发展或是发生改变。

前言

本文章仅做移动安全学习交流用途,严禁作其他用途,如果侵犯您的权益请联系我删除。

所用工具: IDA Pro, frida, jadx

分析

该app带有反调试,在libmaoaidesc.so文件中,用dlsym函数可以hook到调用了pthread_create,与某黑盒,bili是一样的,过检测代码

Point

1.sub_64960中的sub_6551C

jadx

在jadx中搜索关键词isBackground


进去看到

按x查看sign的调用

发现两处,进第二处发现

hook这个方法

经过对比发现

那么可以确定这个就是sign值,按d查看这个m51046b方法

发现传进了三个参数,第一个是url接口,第二个是固定字符串wdi4n2t8edr,第三个暂时不知道是怎么生成的,但是大多数时候值为-1,按d进入函数zcvsd1wr2t,发现
,加载了RequestEncoder这个so文件,进入native层

IDA

直接用findhash插件搜索,定位到函数sub_64A84


可以看出是一个MD5函数,查看此函数调用

sub_6551C函数中,hook该函数,hook代码

function hook_sub_6551C(){
    Java.perform(function () {
        var a45d = Module.findBaseAddress("libRequestEncoder.so")
        a45d = a45d.add(0x6551C)
        Interceptor.attach(a45d,{
            onEnter:function(arg){
                var c_arg1 = arg[1].readCString();
                var c_arg2 = arg[2];
                console.log("参数1:",(arg[1]),c_arg1);
                console.log("参数2:",arg[2],c_arg1);
            },
            onLeave:function(ret){
                console.log("返回值;",(ret),ptr(ret).readCString());//.add(0x1)
                console.log();
            }
        })
    });
}

可以得到

/leo-exam/android/photograph/paper/experiencewdi4n2t8edr7816b3677e8e2e81e2db7602f38a223c/leo-exam/android/photograph/paper/experience2e88d87168558127e673cd8596596cae576175548014621528808779773355443228808783155761755132880877428808783288087697480146228808777155761755576175515181532009753200976576175524007312880877713960292596029252880877915288087799602925288087799602925288087761677721628808779715151515401537985928962618979152400731288087155761755480146201828808737985928962880876971533554432288087772216059480146215261897915221605928808776320097532009761677721628808779ab24139cfb96a255c09ab23cccb986c8wdi4n2t8edr

将该参数分为4段:
字段1:/leo-exam/android/photograph/paper/experiencewdi4n2t8edr为接口+固定字符串wdi4n2t8edr,其MD5的值为7816b3677e8e2e81e2db7602f38a223c
字段2:字段1+MD5(字段1)+接口+MD5(字段1+MD5(字段1)+接口)
字段3:576175548014621528808779773355443228808783155761755132880877428808783288087697480146228808777155761755576175515181532009753200976576175524007312880877713960292596029252880877915288087799602925288087799602925288087761677721628808779715151515401537985928962618979152400731288087155761755480146201828808737985928962880876971533554432288087772216059480146215261897915221605928808776320097532009761677721628808779,不知道生成方式
字段4:ab24139cfb96a255c09ab23cccb986c8wdi4n2t8edr,为MD5(字段1+字段2+字段3)+wdi4n2t8edr


sub_6551C的下面有一个sub_655E4,hook这个函数发现

其最终返回值和sign值相同。


为了hook到注册的RegisterNatives函数,在过检测代码中修改函数hook_dlopen

function hook_dlopen() {
    var interceptor = Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    console.log("[LOAD]", path)
                    if (path.indexOf("libmsaoaidsec.so") > -1) {
                        hook_dlsym()
                    }else if(path.indexOf("libRequestEncoder.so") > -1){
                        hook_RegisterNatives();
                    }
                }
            },
        }
    )
    return interceptor
}

注入启动app,控制台搜索zcvsd1wr2t,得到


即native函数zcvsd1wr2t对应为sub_0x61bd4

[RegisterNatives] java_class: com.fenbi.android.leo.utils.e name: zcvsd1wr2t sig: (Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String; fnPtr: 0x7af4fb2bd4 module_name: libRequestEncoder.so module_base: 0x7af4f51000 offset: 0x61bd4

hook该函数,其返回值就是sign参数


处理一下参数的打印

发现参数2和参数3和参数4正是在java层中传入的参数。(注:因为参数4时带符号位,因此是-1)

hook代码

function hook_sub_61BD4(){
    Java.perform(function () {
        let C14561e = Java.use("com.fenbi.android.leo.utils.e");
        C14561e["zcvsd1wr2t"].implementation = function (str, str2, i) {
            console.log(`C14561e.zcvsd1wr2t is called: str=${str}, str2=${str2}, i=${i}`);
            let result = this["zcvsd1wr2t"](str, str2, i);
            console.log(`C14561e.zcvsd1wr2t result=${result}`);
            return result;
        };

        var a45d = Module.findBaseAddress("libRequestEncoder.so")
        a45d = a45d.add(0x61BD4)
        Interceptor.attach(a45d,{
            onEnter:function(arg){
                var c_arg0 = ptr(arg[0]).readCString();
                var c_arg1 = ptr(arg[1]).readCString();
                var c_arg2 = ptr(arg[2]).readCString();
                var c_arg3 = ptr(arg[3]).readCString();
                var c_arg4 = ptr(arg[4]);
                console.log("参数0:",arg[0],getAsciiLog(arg[0],16), (arg[0]));
                console.log("参数1:",(arg[1]),getAsciiLog(arg[1],16),objectToString(arg[1]));
                console.log("参数2:",(arg[2]),getAsciiLog(arg[2],16),objectToString(arg[2]));
                console.log("参数3:",(arg[3]),getAsciiLog(arg[3],16),objectToString(arg[3]));
                console.log("参数4:",(arg[4]),(arg[4]),(arg[4]));
            },
            onLeave:function(ret){
                console.log("返回值;",ret, objectToString(ret));//.add(0x1)
                console.log();
            }
        })

    });
}

2024-10-11

简单分析判断加密流程:
传接口字符串和固定字符串于sub_61BD4,调用五次sub_64960,在每次sub_64960执行中,又调用三次sub_6551C,即一共调用15次sub_6551C,通过hook函数sub_6551C,发现确实调用了15次,那么按照执行顺序,可以知道每次调用对应的是哪个位置。

/leo-exam/android/photograph/paper/experiencewdi4n2t8edr7816b3677e8e2e81e2db7602f38a223c/leo-exam/android/photograph/paper/experience2e88d87168558127e673cd8596596cae5762155480179616288107817733554432288107831657621552028810774288107832881077774801796288107811657621555762155162116320119732011985762155240089828810774720960359396035932881078116288107819603593288107819603593288107801677721628810781471616161640163631869312261916118240089828810716576215548017960212881073631869312288107777183355443228810781221621348017961626191611622162132881078032011973201198167772162881078196be3984368a5948474cd19ec491c759wdi4n2t8edr
对应sign值ea1af8b12973ab36e8d8f5ca59fffc47
/bh5/leo-web-search/search.htmlwdi4n2t8edrabe0f1a802d83316b79e5f1e51d14d56/bh5/leo-web-search/search.html0483ea40bbbcbdb568adcf6f0e9add5d57621564801797132881081677335544322881078713576215617288107842881078728810784748017972881078613576215657621561317133201198320119957621562400898288107851179603594960359428810816132881081696035942881081696035942881078516777216288108165113131313451375099520261916215240089828810713576215648017975172881077509952028810784715335544322881078622162144801797132619162132216214288107853201198320119916777216288108165998389161498beaf124128a56231d3awdi4n2t8edr
对应sign值6aa4b41358961a5b0ec944285507e69b

将此类型值直接MD5可得到sign

分析此参数

第一段:
第一段为接口+固定字符串wdi4n2t8edr
/bh5/leo-web-search/search.htmlwdi4n2t8edr
第二段:
abe0f1a802d83316b79e5f1e51d14d56,为第一段MD5值
第三段:
/bh5/leo-web-search/search.htmlwdi4n2t8edrabe0f1a802d83316b79e5f1e51d14d56/bh5/leo-web-search/search.html,为:第一段+第二段+接口的MD5值
第四段:
/bh5/leo-web-search/search.htmlwdi4n2t8edrabe0f1a802d83316b79e5f1e51d14d56/bh5/leo-web-search/search.html0483ea40bbbcbdb568adcf6f0e9add5d,为:第三段+第三段的MD5值
第五段:
/bh5/leo-web-search/search.htmlwdi4n2t8edrabe0f1a802d83316b79e5f1e51d14d56/bh5/leo-web-search/search.html0483ea40bbbcbdb568adcf6f0e9add5d5762156480179713288108167733554432288107871357621561728810784288107872881078474801797288107861357621565762156131713320119832011995762156240089828810785117960359496035942881081613288108169603594288108169603594288107851677721628810816511313131345137509952026191621524008982881071357621564801797517288107750995202881078471533554432288107862216214480179713261916213221621428810785320119832011991677721628810816,为第四段
第六段:
5998389161498beaf124128a56231d3a,为第四段MD5值

完整为:第五段+第六段+wdi4n2t8edr

现在只需要分析出5762156480179713288108167733554432288107871357621561728810784288107872881078474801797288107861357621565762156131713320119832011995762156240089828810785117960359496035942881081613288108169603594288108169603594288107851677721628810816511313131345137509952026191621524008982881071357621564801797517288107750995202881078471533554432288107862216214480179713261916213221621428810785320119832011991677721628810816的生成即可还原出sign算法

2024-10-12

上文提到

传接口字符串和固定字符串于sub_61BD4,调用五次sub_64960,在每次sub_64960执行中,又调用三次sub_6551C,即一共调用15次sub_6551C,通过hook函数sub_6551C,发现确实调用了15次,那么按照执行顺序,可以知道每次调用对应的是哪个位置。

在第四次调用sub_64960的时候,参数后加了一个不知道的长数组字符串。

sub_61BD4调用了一次sub_64960,而剩余四次对sub_64960的调用在sub_66A1C中,sub_61BD4中调用的sub_64960传入的参数0为toChars,参数1不知道。

在整个sign生成的过程中,执行了5次sub_64960,首次是sub_61BD4中的一次,其余四次似乎出现在了sub_66A1C中,在第四次执行sub_64960时,参数1多了待解密字符串
ida关键代码应该是

std::string::append((int)v33, v20, v21);
sub_64960((__int64)v38, (__int64)v33);

第一句代码作用是将v20的字符串拼接到v33所指字符串的后面,长度为v21,尝试去hook一下这append函数。hook代码如下:

function hook_append(){
    Java.perform(function(){
        var a45d = Module.findBaseAddress("libRequestEncoder.so")
        // 假设 SO 文件路径为 "libyourlibrary.so",以及函数地址
        var moduleName = "libRequestEncoder.so";
        var symbolName = "_ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKcm"; // C++ 的修饰名

        Interceptor.attach(Module.findExportByName(moduleName, symbolName), {
            onEnter: function (args) {
                // args[0] 是第一个参数 _QWORD *a1
                // args[1] 是第二个参数 void *src
                // args[2] 是第三个参数 unsigned __int64 n
                console.log("std::string::append called");
                console.log("a1: " + args[0]); // 打印 a1
                console.log("src: " + Memory.readUtf8String(args[1])); // 打印 src 内容
                console.log("n: " + args[2].toInt32()); // 打印 n 的值
            },
            onLeave: function (retval) {
                console.log("Return value: " + retval); // 打印返回值
            }
        });

    })
}

hook结果


sub_66A1C中一共出现了7次append函数,我们也hook到了7次append函数,且第五次添加了未知字符串,而第五次对应的正好就是上面贴出的伪代码,因此可以确定,v20就是这个未知字符串的地址。

那么现在的任务就是分析v20是怎么来的

2024-10-13
通过对java层hook函数入参的修改,发现当传入接口字符串固定时,在一小段时间内,所有sign值相同,一段时间后,sign值开始变化成另外一个sign,并持续一小段时间。

经过观察发现,这一小段时间是60秒,每60秒内,无论接口字符串是什么,所有未解密参数的值都是相同的,且即使将固定字符串修改为不同的值,所有未解密参数的值也都是相同的,也就是说,未解密字符串的生成与时间有关,与接口字符串和固定字符串无关。

看汇编代码

.text:0000000000066B5C 41 01 89 9A                   CSEL            X1, X10, X9, EQ         ; src

CSEL X1, X10, X9, EQ 的意思是:
如果之前的条件(通常是由 CMP 指令产生的)满足 EQ,则 X1 将取 X10 的值。
否则,X1 将取 X9 的值。
这条指令可以用于根据条件来决定赋值给目标寄存器的内容。

再通过代码查看寄存器的值

//在hook_append函数中
console.log('X10:', this.context.x10.readCString());    // X10 寄存器的值
console.log('X9:', this.context.x9.readCString());    // X9 寄存器的值


可以看到,X9寄存器中存放着待解密字符串。那么就是,前面的代码中存在将待解密字符串放到寄存器X9的操作,那么我们可以再hook一下这个sub_66A1C函数,看一下在刚开始调用时X9寄存器是否就已经放着待解密字符串,如果没有,那么待解密字符串的来源就可以锁定在这个sub_66A1C的内部;如果有,那么就需要做另外的分析了。


hook发现其中并没有放着待解密字符串,而是api接口,那么正如前面所说,待解密字符串的来源就锁定在这块代码中了。

sub_61BD4调用了sub_66A1C

sp+0x40,bp-0x80

2024-10-14

sub_67198每次的返回值都为待解密字符串

观察sub_65784函数,其为sub_67198所调用
5762156480179713288108167733554432288107871357621561728810784288107872881078474801797288107861357621565762156131713320119832011995762156240089828810785117960359496035942881081613288108169603594288108169603594288107851677721628810816511313131345137509952026191621524008982881071357621564801797517288107750995202881078471533554432288107862216214480179713261916213221621428810785320119832011991677721628810816
再看这段字符串,其中的28810785为(时间戳-1)/60

2024-10-15

我们这里拿57632614802717162881630877335544322881631116576326118288163042881631128816304748027172881631016576326157632611619163201811320181257632612401358288163021189605435960543528816308162881630896054352881630896054352881630516777216288163082116161616411613053413122619664172401358288163165763261480271711928816313053413122881630471733554432288163102216638480271716261966416221663828816305320181132018121677721628816308来作为例子分析其是如何构造组成的。

首先需要说明的是,此例子参数对应的时间戳为1728978392

这里设a2-1通过代码*(_QWORD *)timer = (*(_QWORD *)timer + a2) / 60LL;计算后,timer被赋值为28816306

先定义一些函数

def HIWORD(value):
    return (value >> 16) & 0xFFFF

def LOBYTE(value):
    return value & 0xFF  # 取低8位

def HIBYTE(value):
    return (value >> 8) & 0xFF  # 右移8位后取低8位

def LOBYTE(w):
    return w & 0xFF

伪代码块1


然后将此值赋给v3,并进行计算,这里的伪代码用Python实现为:

# block 1
timer_0 = 28816306
v3 = timer_0
v167 = timer_0 >> 4
v157 = timer_0 >> 3
v4 = v157 + v167 + ((v157 + v167) >> 4) + ((v157 + v167 + ((v157 + v167) >> 4)) >> 8)
v5 = v4 + HIWORD(v4) + ((13 * (timer_0 - 5 * (v4 + HIWORD(v4)))) >> 6)
print("第一个 => ",v5)
# 输出 => 5763261

伪代码块2


Python实现:

v6 = v3 + (v3 >> 31)
v170 = v6
v160 = v6 >> 3
v7 = (v6 >> 3) + (v6 >> 5) + (((v6 >> 3) + (v6 >> 5)) >> 4)
v8 = v7 + (v7 >> 8) + ((v7 + (v7 >> 8)) >> 16)
v9 = v8 + ((11 * (v6 - 6 * v8)) >> 6)
print("第二个 => ",v9)
# 输出 => 4802717

伪代码块3


Python实现:

v171 = v3 >> 1
v10 = ((((v171 & 0x55555555) + (v3 & 0x55555555)) >> 2) & 0x33333333)+ (((v171 & 0x55555555) + (v3 & 0x55555555)) & 0x33333333)
v11 = (((((v10 >> 4) & 0x7070707) + (v10 & 0x7070707)) >> 8) & 0xF000F)+ ((((v10 >> 4) & 0x7070707) + (v10 & 0x7070707)) & 0xF000F)
v12 = (v11 & 0x1F) + HIWORD(v11)
print("第三块 => ",v12)
# 输出 => 16

伪代码块4


Python实现:

v13 = HIWORD(v3)
v169 = v13
v165 = -v3 & v3
v172 = v165 + v3

if v3 != 0:
    if v3 & 0xFFFF:
        v13 = v3
    if v3 & 0xFFFF:
        v14 = 1
    else:
        v14 = 17
    v15 = (v13 & 0xFF) == 0
    if (v13 & 0xFF) == 0:
        v13 >>= 8
    if v15:
        v14 |= 8
    v16 = (v13 & 0xF) == 0
    if (v13 & 0xF) == 0:
        v13 >>= 4
    if v16:
        v14 |= 4
    v17 = (v13 & 3) == 0
    if (v13 & 3) == 0:
        v13 >>= 2  # LOBYTE(v13) = v13 >> 2
    if v17:
        v14 |= 2
    v18 = v14 - (v13 & 1) + 2
else:
    v18 = 34
block4_value = ((v172 ^ v3) >> v18) | v172
print("第四块 => ",block4_value)
# 输出 => 28816308

伪代码块5,6


注:这里执行了两遍std::ostream::operator<<(&v174, v24);,也就是拼接了两次,第5和6是重复的。
Python实现:

if ( v3 ):
    v19 = v3 << 16
    if ( v3 >= 0x10000 ):
        v19 = v3
    v20 = HIBYTE(v19) == 0
    if ( not HIBYTE(v19) ):
        v19 <<= 8
    if ( v20 ):
        v21 = (16 * (v3 < 0x10000)) | 8
    else:
        v21 = 16 * (v3 < 0x10000)
    v22 = v19 >> 28 == 0
    if ( not (v19 >> 28) ):
        v19 *= 16
    if ( v22 ):
        v21 |= 4
    v23 = v19 >> 30 == 0
    if ( not (v19 >> 30) ):
        v19 *= 4
    if ( v23 ):
        v21 |= 2
    v24 = v21 + ((v19 & 0x80000000) == 0)
else:
    v24 = 32
print("第五块 => ",v24)
print("第六块 => ",v24)
# 输出 => 7
# 输出 => 7

伪代码块7


Python实现:

v25 = (v3 - 1) | ((v3 - 1) >> 1) | (((v3 - 1) | ((v3 - 1) >> 1)) >> 2)
v26 = v25 | (v25 >> 4) | ((v25 | (v25 >> 4)) >> 8)
v159 = (v26 | HIWORD(v26)) + 1
print("第七块 => ",v159)
# 输出 => 33554432

伪代码块8,9,10


v12v5都是已知值,只需关注v33 | v34
Python实现:

v27 = v3 + 1
v28 = v3 + 3
v29 = v3 + 2
v30 = (v3 + 3) & (v3 + 1)
v31 = 0x80000000  # 相当于 2^31

while v31 > 1:
    if (v31 & v30) != 0:
        v34 = (v27 - v31) | (v31 - 1)
        if v34 >= v3:
            v33 = v3 + 3
            break
        v33 = (v28 - v31) | (v31 - 1)
        if v33 >= v29:
            v34 = v3 + 1
            break
    v31 >>= 1  # 相当于右移一位

# 如果循环结束,计算默认值
if v31 == 1:
    v34 = v3 + 1
    v33 = v3 + 3
block8_value = v33 | v34
print("第八块 => ",block8_value)
print("第九块 => ",v12)
print("第十块 => ",v5)
# 输出 => 28816311
# 输出 => 16
# 输出 => 5763261

伪代码块11(暂未复现)

伪代码块12


Python实现:

v142 = v170 >> 1
v36 = (v170 >> 1) + (v170 >> 2) + (((v170 >> 1) + (v170 >> 2)) >> 4)
v37 = (v36 + (v36 >> 8) + ((v36 + (v36 >> 8)) >> 16)) >> 3
v135 = v37 + ((v170 - 10 * v37 + 6) >> 4)
print("第十二块 => ",v135)
# 输出 => 2881630

伪代码块13(暂未复现)


Python实现:

伪代码块14


Python实现:

v41 = 0x80000000
while True:
    if (v41 & v30) != 0:
        v43 = (v27 - v41) | (v41 - 1)
        if v43 >= v3:
            break  # LABEL_59
        v42 = (v28 - v41) | (v41 - 1)
        if v42 >= v29:
            v43 = v3 + 1
            break  # LABEL_60
    v32 = v41 > 1
    v41 >>= 1
    if not v32:
        v43 = v3 + 1
        break

v42 = v3 + 3  # After LABEL_59
result = v42 | v43  # After LABEL_60
print("第十四块 => ",result)
# 输出 => 28816311

伪代码块15(暂未复现)

伪代码块16,17


Python实现:

dword_42BE0 = [0, 9, 0x63, 0x3E7, 0x270F, 0x1869F, 0xF423F, 0x98967F, 0x5F5E0FF, 0x3B9AC9FF, 0xFFFFFFFF]
v47 = -2
while True:
    v48 = v47 + 2
    v47 = v47 + 1
    if dword_42BE0[v48] >= v3:
        break
print("第十六块 => ",v47)
print("第十七块 => ",v9)
# 输出 => 7
# 输出 => 4802717

伪代码块18(暂未复现)

伪代码块19(暂未复现)


Python实现:

伪代码块20


Python实现:

v54 = v3 >> 2
v55 = v171 + (v3 >> 2)
v56 = v55 + (v55 >> 4) + ((v55 + (v55 >> 4)) >> 8)
v57 = (v56 + (v56 >> 16)) >> 2  # Assuming HIWORD is equivalent to shifting right by 16 bits
v58 = v3 - 5 * v57
v140 = v57 + ((7 * v58) >> 5)
print("第二十块 => ",v140)  # Assuming v174 is a file-like object
# 输出 => 5763261

伪代码块21


Python实现:

if v58 <= 4:
    v59 = v57
else:
    v59 = v57 + 1

if v58 <= 9:
    v60 = v59
else:
    v60 = v59 + 1

v148 = v60
print("第二十一块",v60)
# 输出 => 5763261

伪代码块22


Python实现:

2024-10-18

伪代码块

中间写着太麻烦了,道理是一样的,这里就省去了,只对伪代码块30进行分析。

伪代码块30

v66.n64_u64[0] = veor_s8((int8x8_t)__PAIR64__(v171, v54), vdup_n_s32(v3)).n64_u64[0];
v67 = v66.n64_u32[1];
v68.n128_u64[0] = veor_s8(vshr_n_u32(v66, 4uLL), v66).n64_u64[0];
v68.n128_u32[2] = v67 ^ (v67 >> 2);
v68.n128_u32[3] = v68.n128_u32[2];
v69 = veorq_s8(vshlq_u32(v68, (uint32x4_t)xmmword_42890), v68);
v70 = vandq_s8(
    veorq_s8(vshlq_u32(v69, (uint32x4_t)xmmword_42870), vshlq_u32(v69, (uint32x4_t)xmmword_42850)),
    (int8x16_t)xmmword_42910);
v69.n128_u64[0] = vorr_s8((int8x8_t)v70.n128_u64[0], (int8x8_t)vextq_s8(v70, v70, 8uLL).n128_u64[0]).n64_u64[0];
v136 = (v69.n128_u32[0] | v69.n128_u32[1] | ((v69.n128_u32[3] ^ (v69.n128_u32[3] >> 8)) >> 12) & 0x10 | (32 * (((unsigned __int8)(v69.n128_u8[12] ^ v69.n128_u8[13]) ^ (unsigned __int8)((v69.n128_u32[3] ^ (v69.n128_u32[3] >> 8)) >> 16)) & 1))) ^ -(v3 & 1) & 0x3F;
std::ostream::operator<<(&v174, v136);

此代码涉及到向量数组运算,且v66,v68,v69,v70为c++中的联合体。

PAIR64

在IDA的头文件摘录中可以找到

#define __PAIR64__(high, low)   (((uint64) (high) << 32) | (uint32)(low))

详细可以看这篇文章,IDA头文件摘录

veor_s8,vdup_n_s32,vshr_n_u32,veorq_s8,vshlq_u32,vandq_s8,vorr_s8,vextq_s8

这些函数在SIMD指令集中可以找到,可以去这个网站找指令集

veor_s8

Bitwise Exclusive OR (vector). This instruction performs a bitwise Exclusive OR operation between the two source SIMD&FP registers, and places the result in the destination SIMD&FP register.

指的是向量按位异或运算。可以用Python来实现
np.logical_xor(a, b)

vdup_n_s32

vdup_n_s32 的作用是将给定的标量(一个 32 位的整数)填充到一个 128 位的向量中的每个位置,具体来说,它会生成一个包含 4 个 32 位元素的向量,而这 4 个元素的值是一样的。

Python实现:

# vdup_n_s32(v3)
np.array([v3,v3,v3,v3])

2024-10-26


(上面有具体代码)
看了好几天,这部分实在是复现不出来,其他部分的都已经实现,如果有能复现出来这段的可以跟我交换一下其他部分的,或者有思路的也可以一起交流一下。


(部分复现代码)

这里给出一个可以用来复现时验证的例子

# 那段代码中会用到的参数
v3 = 28818947
v171 = v3 >> 1
v54  = v3 >> 2
# 有了这些参数后,经过那段代码计算后可以得到v136的值为5
# 注:你可能算出来的结果是0或63,这两个值是不正确的,说明还没有复现成功

关于这四个参数:xmmword_42890,xmmword_42870,xmmword_42850,xmmword_42910
在IDA中为

.rodata:0000000000042890 F8 FF FF FF F8 FF FF FF F8 FF+xmmword_42890 DCB 0xF8, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF
.rodata:0000000000042870 FF FF FF FF EF FF FF FF EE FF+xmmword_42870 DCB 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xEE, 0xFF, 0xFF, 0xFF, 0xEB, 0xFF, 0xFF, 0xFF
.rodata:0000000000042850 EF FF FF FF FF FF FF FF FE FF+xmmword_42850 DCB 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF
.rodata:0000000000042910 01 00 00 00 02 00 00 00 04 00+xmmword_42910 DCB 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0
转载请注明:
作者:syy,出处:https://www.94i.top/index.php/2024/10/09/某猿口算sign分析/
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇