在Unidbg文章中, 我们尝试过多次主动调用, 文中可以发现, 只有253b8c85 这个的key是不变的.

image-20241217140300974

Unidbg运行一遍,搜索运行下这个Key, 我们在下面的堆栈中, 可以看到memcpy的调用地址为0x0498ec

image-20241217140524043

Unidbg trace整个流程, 在010editor中搜索253b8c85

可以发现,我们这个数据首次发现的位置位于0x1bfb54偏移处.

image-20241217145718955

可以知道我们的结果是由 0xa53b8c85 & 0x7fffffff得到的.

[14:54:36 435][libshpssdk.so 0x1bfb54] [ab010b0a] 0x401bfb54: "and w11, w13, w11" w13=0x7fffffff w11=0xa53b8c85 => w11=0x253b8c85 // w11 = w13 & w11

w13又是固定的. 所以我们需要找到0xa53b8c85是如何生成的

image-20241217155446249

💡分析trace, 我们应该以结果为导向. 只关注于我们需要的数据. 一些其他无用的运算我们应该选择性跳过. 一行行分析下去十分的疲惫.

搜索0xa53b8c85, 找到第一次出现的地方.

image-20241217155623792

w14 = w1 + w14 , w1 比较简单, 我们先分析复杂的.

[14:54:36 426][libshpssdk.so 0x1bfe28] [2e000e0b] 0x401bfe28: "add w14, w1, w14" w1=0x65 w14=0xa53b8c20 => w14=0xa53b8c85

搜索0xa53b8c20, 找到第一次出现的地方

w11 = w11 * w13

[14:54:36 423][libshpssdk.so 0x1bfcb0] [6b7d0d1b] 0x401bfcb0: "mul w11, w11, w13" w11=0x334b w13=0xa1f6f060 => w11=0xa53b8c20

搜索0xa1f6f060, 找到第一次出现的地方

w14 = w1 + w14

[14:54:36 416][libshpssdk.so 0x1bfe28] [2e000e0b] 0x401bfe28: "add w14, w1, w14" w1=0x75 w14=0xa1f6efeb => w14=0xa1f6f060

搜索0xa1f6efeb, 找到第一次出现的地方

w11 = w11 * 13

[14:54:36 413][libshpssdk.so 0x1bfcb0] [6b7d0d1b] 0x401bfcb0: "mul w11, w11, w13" w11=0x334b w13=0xf419b1e1 => w11=0xa1f6efeb

搜索0xf419b1e1, 找到第一次出现的地方

w14 = w1 + w14

[14:54:36 406][libshpssdk.so 0x1bfe28] [2e000e0b] 0x401bfe28: "add w14, w1, w14" w1=0x72 w14=0xf419b16f => w14=0xf419b1e1

搜索0xf419b16f,找到第一次出现的地方

w11 = w11 * w13

[14:54:36 403][libshpssdk.so 0x1bfcb0] [6b7d0d1b] 0x401bfcb0: "mul w11, w11, w13" w11=0x334b w13=0x8c687fed => w11=0xf419b16f

有兴趣的继续找下去. 我是比较累了. 我们再来看看规律.

[14:54:36 403][libshpssdk.so 0x1bfcb0] [6b7d0d1b] 0x401bfcb0: "mul w11, w11, w13" w11=0x334b w13=0x8c687fed => w11=0xf419b16f
[14:54:36 406][libshpssdk.so 0x1bfe28] [2e000e0b] 0x401bfe28: "add w14, w1, w14" w1=0x72 w14=0xf419b16f => w14=0xf419b1e1
[14:54:36 413][libshpssdk.so 0x1bfcb0] [6b7d0d1b] 0x401bfcb0: "mul w11, w11, w13" w11=0x334b w13=0xf419b1e1 => w11=0xa1f6efeb
[14:54:36 416][libshpssdk.so 0x1bfe28] [2e000e0b] 0x401bfe28: "add w14, w1, w14" w1=0x75 w14=0xa1f6efeb => w14=0xa1f6f060
[14:54:36 423][libshpssdk.so 0x1bfcb0] [6b7d0d1b] 0x401bfcb0: "mul w11, w11, w13" w11=0x334b w13=0xa1f6f060 => w11=0xa53b8c20
[14:54:36 426][libshpssdk.so 0x1bfe28] [2e000e0b] 0x401bfe28: "add w14, w1, w14" w1=0x65 w14=0xa53b8c20 => w14=0xa53b8c85
[14:54:36 435][libshpssdk.so 0x1bfb54] [ab010b0a] 0x401bfb54: "and w11, w13, w11" w13=0x7fffffff w11=0xa53b8c85 => w11=0x253b8c85 // w11 = w13 & w11

通过上面的跟值找值, 可以发现我们最终的结果. 可以大致的翻译成如下大白话:

循环(条件未知){
    结果 =  (上一次运算的结果 * 0x334b + 未知的字节)
}
结果 = 结果 & 0x7fffffff

因为可以猜测到循环, 并且, 我们目前需要知道,这个未知的字节是什么?

所以我再次搜索0x401bfe28: "add w14, w1, w14" w1=

我们只需要,这个框框选择出来的长的指令. 所以我们匹配到的结果

image-20241217161242097

手动处理了一点数据, 把选择的字节提取出来.

image-20241217161816066

惊奇的发现.这数据有点好看.

image-20241217161906791

没错,这就是我们的URL

image-20241217162008817

并且开头是以0x00开始的

image-20241217162133515

所以, 我们就可以写一个算法进行验证了


url = "/api/v4/search/search_page_common?by=relevancy&extra_param=%7B%22global_search_session_id%22%3A%22NqAYm66NYy45DbQoklaKEBuaQD%2BQgayKLEeqNuK3MhM%3D-1734075545797-global%22%2C%22search_session_id%22%3A%22NqAYm66NYy45DbQoklaKEBuaQD%2BQgayKLEeqNuK3MhM%3D-1734075560832-search%22%7D&keyword=ab&newest=0&order=desc&page=1&page_type=search&scenario=PAGE_GLOBAL_SEARCH&version=2&view_session_id=NqAYm66NYy45DbQoklaKEBuaQD%2BQgayKLEeqNuK3MhM%3D-1734075560832&with_filter_config=true"
result = 0
for i in url:
    b = i.encode('utf-8')
    # 使用 & 0xffffffff 可以模拟 C/C++ 等语言中 uint32_t 的行为
    # 保证结果始终在 0 到 4294967295 之间"
    b = ord(b) & 0xffffffff
    result = (result * 0x334b + b) & 0xffffffff
    # toHex
    print(hex(result))
result = result & 0x7fffffff
print(f"{result:04x}")

运算结果正确.

image-20241217164932715