密码学学习记录|hash sha1 算法练习样本一

密码学学习记录 6 / 18

样本来自 Litt1eQ 大佬的公众号 Coder小Q

推荐阅读上一章的 sha1 算法分析

分析之前先使用 unidbg 跑一下,方便动态调试分析

这个样本跟前面的 md5 逻辑比较相似,打开即可分析

so 分析

这是入口函数,核心逻辑在 sub_950

这里有几个常量,点过去看一下

这里有五个,猜测是 H0-H4 五个常量

在往下就是,数据分组跟四轮循环了

sub_91C 这个函数的逻辑,就是四个 F 函数了

unidbg

使用 unidbg 获取一些常常量值

  • 1、H0-H4 五个常量

  • 2、四个计算常数

  • 3、循环移位数

0x1 五个常量 hook

emulator.getBackend().hook_add_new(new CodeHook() {
    @Override
    public void hook(Backend backend, long address, int size, Object user) {
        if (address == (module.base + 0xA00)) {
            Arm32RegisterContext ctx = emulator.getContext();

            System.out.println("0xA00 五个常量: 0x" + Long.toHexString(ctx.getR1Long()));
        }
    }

    @Override
    public void onAttach(UnHook unHook) {

    }

    @Override
    public void detach() {

    }
}, module.base + 0xA00, module.base + 0xA00, null);

0x2 四个计算常数 hook

emulator.getBackend().hook_add_new(new CodeHook() {
    @Override
    public void hook(Backend backend, long address, int size, Object user) {
        if (address == (module.base + 0xA44)) {
            Arm32RegisterContext ctx = emulator.getContext();

            System.out.println("0xA44 K params = 0x" + Long.toHexString(ctx.getR1Long()));
        }
    }

    @Override
    public void onAttach(UnHook unHook) {

    }

    @Override
    public void detach() {

    }
}, module.base + 0xA44, module.base + 0xA44, null);

计算常数有些不同,标准的只有四个,四轮每轮使用一个,这里的却是有 80 个,也就是每步都是不同的

0x3 循环移位数

这个不需要 hook 静态分析就能看出来(不过需要注意,标准的是循环左移,这里是循环右移)

数组分组时,循环右移数是 31

80 步计算时,循环右移使用的分别是 27, 2

python

使用之前的代码改改就可以

  • 1、H0-H4 五个常量
self.H = [0x1B6E192E, 0x3FC176B7, 0x5F973152, 0x6DCC57BB, 0x7AEA38C1]
  • 2、计算常数
self.K = [
    0xDF173709, 0xCCB9E3D2, 0x73CAF584, 0xA5FAF9A5, 0xF36AAC58, 0xA2C7B75E, 0x76888D8F, 0x3E9E8A08,
    0xDB22622E, 0x4CF63C0F, 0x7E714178, 0x2326FDCF, 0x26CE914A, 0x3CB69463, 0x870A24BC, 0x2441A25,
    0x96913352, 0x22889709, 0x222EC95F, 0x2DC2CAFD, 0x461173C7, 0x480BC543, 0xE31BCB1C, 0x67C3C909,
    0x7112F5F3, 0xA937B122, 0x5021BCE9, 0x9F9DA0C5, 0x794BEBE8, 0xC01EDC7C, 0xD73CC8F5, 0x4F707435,
    0x9D537008, 0x1E01CC36, 0x2920CC22, 0x4A986749, 0x7F965009, 0x4884B90, 0x9EA9963E, 0x162C4DEB,
    0x1FE109E8, 0x333B89FC, 0x2C43BC20, 0x459B474C, 0xE730A765, 0xDA34245, 0x6E606232, 0xAC7E29D4,
    0x2EDED96B, 0x9C7C6EB3, 0x7C153F9F, 0x54B308E1, 0xD365ECEB, 0x51EE2ABD, 0, 0, 0, 0, 0, 0, 0,
    0x1B6E192E, 0x3FC176B7, 0x5F973152, 0x6DCC57BB, 0x7AEA38C1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
  • 3、循环右移
@staticmethod
def left_circular_shift(k, bits):
    bits = bits % (2 ** 32)
    k = k % (2 ** 32)
    return (k << (32 - bits) | (k >> bits)) % (2 ** 32)
  • 4、transform
def transform(self, input_str):
    iterations = (len(input_str) * 8) // 512

    for i in range(0, iterations):
        input_str1 = input_str[i * 64: (i + 1) * 64]

        A = self.H[0]
        B = self.H[1]
        C = self.H[2]
        D = self.H[3]
        E = self.H[4]
        W = [0] * 80

        for w1 in range(16):
            W[w1] = (input_str1[w1 * 4]) << 24
            W[w1] |= (input_str1[w1 * 4 + 1]) << 16
            W[w1] |= (input_str1[w1 * 4 + 2]) << 8
            W[w1] |= (input_str1[w1 * 4 + 3]) << 0

        for w2 in range(16, 80):
            W[w2] = self.left_circular_shift(W[w2 - 3] ^ W[w2 - 8] ^ W[w2 - 14] ^ W[w2 - 16], 31)

        for f in range(80):
            if f < 20:
                f_res = ((B & C) | ((~B) & D)) % (2 ** 32)

            elif f < 40:
                f_res = (B ^ C ^ D) % (2 ** 32)

            elif f < 60:
                f_res = ((B & C) | (B & D) | (C & D)) % (2 ** 32)

            elif f < 80:
                f_res = (B ^ C ^ D) % (2 ** 32)

            else:
                f_res = 0

            TEMP = self.left_circular_shift(A, 27) + f_res + E + W[f] + self.K[f]
            TEMP = TEMP % (2 ** 32)
            E = D
            D = C
            C = self.left_circular_shift(B, 2)
            B = A
            A = TEMP

        self.H[0] = (self.H[0] + A) % (2 ** 32)
        self.H[1] = (self.H[1] + B) % (2 ** 32)
        self.H[2] = (self.H[2] + C) % (2 ** 32)
        self.H[3] = (self.H[3] + D) % (2 ** 32)
        self.H[4] = (self.H[4] + E) % (2 ** 32)

    return ''.join([hex(i).replace('0x', '').rjust(8, '0') for i in self.H]).upper()

最后

执行代码,结果跟 unidbg 的结果相同(这里有个很离谱的问题,unidbg 的结果跟 app 的不同,有哪位巨佬知晓原因还望指教)

3 条评论
本文作者:
本文链接: https://www.qinless.com/?p=1266
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 qinless 的博客!
100

3 条评论

everhu

这个apk支持64位的指令,如果你的手机也支持64位的指令,它会调用v8a的so,两个so的sha1结果不一样

回复

会爬山的小脑虎

@everhu 原来如此,多谢巨佬指点迷津

回复

everhu

@会爬山的小脑虎 别这么说,我也是看着你的文章学习的,刚好这个问题我之前碰到过

发表评论

返回顶部