吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1359|回复: 2
收起左侧

[原创] 一点简单的分析sha256的想法

[复制链接]
白龙第一分龙 发表于 2023-3-2 22:19

为了避免任何不必要的麻烦,仅仅提供思路,不提供分析的样本下载,仅仅是自己学习和交流,不便之处请见谅。

0x0 前言

阅读本文大概需要浪费20分钟时间

需要一份trace后的汇编执行流(可以通过unidbg获取)

0x1 sha256

没什么特别的理由选它,只是因为刚好看到了,首先看它的伪代码

Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 232
Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 ≤ i ≤ 63
Note 3: The compression function uses 8 working variables, a through h
Note 4: Big-endian convention is used when expressing the constants in this pseudocode,
    and when parsing message block data from bytes to words, for example,
    the first word of the input message "abc" after padding is 0x61626380

Initialize hash values:
(first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19

Initialize array of round constants:
(first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
k[0..63] :=
   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2

Pre-processing (Padding):
begin with the original message of length L bits
append a single '1' bit
append K '0' bits, where K is the minimum number >= 0 such that (L + 1 + K + 64) is a multiple of 512
append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits
such that the bits in the message are: <original message of length L> 1 <K zeros> <L as 64 bit integer> , (the number of bits will be a multiple of 512)

Process the message in successive 512-bit chunks:
break message into 512-bit chunks
for each chunk
    create a 64-entry message schedule array w[0..63] of 32-bit words
    (The initial values in w[0..63] don't matter, so many implementations zero them here)
    copy chunk into first 16 words w[0..15] of the message schedule array

    Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array:
    for i from 16 to 63
        s0 := (w[i-15] rightrotate  7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift  3)
        s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
        w[i] := w[i-16] + s0 + w[i-7] + s1

    Initialize working variables to current hash value:
    a := h0
    b := h1
    c := h2
    d := h3
    e := h4
    f := h5
    g := h6
    h := h7

    Compression function main loop:
    for i from 0 to 63
        S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
        ch := (e and f) xor ((not e) and g)
        temp1 := h + S1 + ch + k[i] + w[i]
        S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
        maj := (a and b) xor (a and c) xor (b and c)
        temp2 := S0 + maj

        h := g
        g := f
        f := e
        e := d + temp1
        d := c
        c := b
        b := a
        a := temp1 + temp2

    Add the compressed chunk to the current hash value:
    h0 := h0 + a
    h1 := h1 + b
    h2 := h2 + c
    h3 := h3 + d
    h4 := h4 + e
    h5 := h5 + f
    h6 := h6 + g
    h7 := h7 + h

Produce the final hash value (big-endian):
digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7

findcrypto等静态识别插件的识别点是魔数或者k表,但一来这部分很容易在未运行时加密,运行时才动态解密,二来它是个很容易的魔改点,所以我选择的识别点在

    Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array:
    for i from 16 to 63
        s0 := (w[i-15] rightrotate  7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift  3)
        s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
        w[i] := w[i-16] + s0 + w[i-7] + s1

主要原因: 1461677324224_.pic.jpg
次要原因 :这一处的代码如果不做特殊处理,很大概率会被编译在一个基本块,其次这是个足够次数的循环(48次),它的特征足够多,9次运算

#一条trace的栗子: 0x400512dc: "bne #0x400512ca"
trace.pc =  0x400512dc
trace.insn =  bne
trace.rd = 0x400512ca
if "bne" in trace.insn or "beq" in trace.insn :
#筛选出条件跳转的执行流
    call_line = trace.pc - trace.rd
    if  0 < call_line < 100:
    #往一个更低的地址跳,循环体的大小有待商榷
        if alltrace.pc.count(trace.pc) == 48:  
            输出trace.dst -> trace.pc 的汇编

然后可以得到48的倍数次的基本块,可以从其中找到一个典型的trace块

[04eb8002] 0x40025dee: "add.w r2, r4, r0, lsl #2" r4=0xbffff2e8 r0=0x0 => r2=0xbffff2e8
[0130    ] 0x40025df2: "adds r0, #1" r0=0x0 => r0=0x1
[3028    ] 0x40025df4: "cmp r0, #0x30" r0=0x1 => cpsr: N=1, Z=0, C=0, V=0
[966b    ] 0x40025df6: "ldr r6, [r2, #0x38]" r2=0xbffff2e8 => r6=0x61336165
[5368    ] 0x40025df8: "ldr r3, [r2, #4]" r2=0xbffff2e8 => r3=0x742f6170
[576a    ] 0x40025dfa: "ldr r7, [r2, #0x24]" r2=0xbffff2e8 => r7=0x32333765
[4feaf645] 0x40025dfc: "ror.w r5, r6, #0x13" r6=0x61336165 => r5=0x6c2cac26
[85ea9625] 0x40025e00: "eor.w r5, r5, r6, lsr #10" r5=0x6c2cac26 r6=0x61336165 => r5=0x6c34e0fe
[3944    ] 0x40025e04: "add r1, r7" r1=0x2f726573 r7=0x32333765 => r1=0x61a59cd8
[85ea7646] 0x40025e06: "eor.w r6, r5, r6, ror #17" r5=0x6c34e0fe r6=0x61336165 => r6=0xdc865067
[4feab345] 0x40025e0a: "ror.w r5, r3, #0x12" r3=0x742f6170 => r5=0xd85c1d0b
[85ead305] 0x40025e0e: "eor.w r5, r5, r3, lsr #3" r5=0xd85c1d0b r3=0x742f6170 => r5=0xd6d9f125
[85eaf315] 0x40025e12: "eor.w r5, r5, r3, ror #7" r5=0xd6d9f125 r3=0x742f6170 => r5=0x3631afe7
[2944    ] 0x40025e16: "add r1, r5" r1=0x61a59cd8 r5=0x3631afe7 => r1=0x97d74cbf
[3144    ] 0x40025e18: "add r1, r6" r1=0x97d74cbf r6=0xdc865067 => r1=0x745d9d26
[1164    ] 0x40025e1a: "str r1, [r2, #0x40]" r1=0x745d9d26 r2=0xbffff2e8
[1946    ] 0x40025e1c: "mov r1, r3" r3=0x742f6170 => r1=0x742f6170
[e6d1    ] 0x40025e1e: "bne #0x40025dee"

9处运算指令与上面的伪代码一一对应,0x40025df4控制循环次数48次,输出w[i-16],整个循环体中,除了循环条件外开始的第一个add,即0x40025e16 中的r1,也就是疑似填充后的明文块,验证是否确实为sha256的方法来自于伪代码中的

append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits
such that the bits in the message are: <original message of length L> 1 <K zeros> <L as 64 bit integer> , (the number of bits will be a multiple of 512)

即判断明文块的末尾附加的长度是否等于消息的长度,大致格式如下

00000000  d8 9c a5 61 35 30 33 34 33 38 33 36 32 30 80 00  |Ø.¥a5034383620..|
00000010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70  |...............p|

同理可得输出的密文,这个方法在微调(嗯,微调)之后可以在我分析过的样本上,可以比较快速的处理sha256(嗯,没错,就分析了一两个)

0x2 尾声

目前看来这个分析方法不进行微调的话,适用范围不高,仅仅只能处理经过ollvm中的fla和bcf的混淆,对于其他混淆,下次在讲

免费评分

参与人数 3威望 +1 吾爱币 +23 热心值 +3 收起 理由
UncleMing + 1 + 1 我很赞同!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
奔奔like + 2 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

无头草 发表于 2023-3-4 12:52
学习一下你的好东西
xixicoco 发表于 2023-3-5 00:21
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-13 15:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表