ezCsky

ezCsky固件逆向,使用ida arm架构打开可以看到rc4_int rc4_crypto 等字符串,猜测为rc4加密,testkey为rc4的key,有一组数据猜测为enc,进行rc4解密后,得到0a0d061c1f545653575100031d14585603191c0054034b14580702494c020701510c0800010003004f7d,尝试发现第一位异或"f",之后相邻异或可得flag

dump

提供了一个re.exe和一个加密后的flag二进制文件。
我们可以注意到re.exe会读取程序参数,所以我们输入:

C:\Users\Administrator\Desktop\bin>re.exe ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
02030405060708090a0b0c0d0e0f101112131415161718191a1b1e1f202122232425262728292a2b2c2d2e2f3031323334353637001c1d00000000000000000001
C:\Users\Administrator\Desktop\bin>re.exe `1234567890-=[]\';,./~!@#$%^&*()_+{}:"?
001c1d00000000000000000001000000000000000000000000000000000000000038390000

我们就可以得到字符表和输出的对应关系,发现是hex,而且是一一对应,除了3~9这几个数字和+/号,还有{},我们容易验证flag二进制文件的前几个就是flag{,最后一个是},所以人工进行一一对照就行。
2024-12-15T08:28:34.png

23 29 1E 24 38 0E 15 20 37 0E 05 20 00 0E 37 12 1D 0F 24 01 01 39
f  l  a  g  {  M  T  c  z  M  D  c  0  M  z  Q   2  N  g  1  1  }

但是问题是,这个flag交上去是错的,原因是因为数字的对应关系, 0是00,3~9也都是00,所以我们手动尝试一下3~9的数字,发现4是对的。所以这个程序的编码是有缺陷的,还好只有一个位置需要猜。
所以flag如下。中间那串是base64,解出来是一个时间戳,应该是出题人出题的时候的时间。

flag{MTczMDc4MzQ2Ng==}

Rand0m

Cython 逆向,pyd里面
x64dbg Hook
由于Python虚拟机的Number都是30bit,所以我经过了如下的处理来还原。
2024-12-15T08:29:03.png

PyNumber_And
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) & ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} & 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_Add
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) + ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} + 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_Xor
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) ^ ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} ^ 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_LShift
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) << ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} << 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_RShift
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) >> ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} >> 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_Reminder
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) % ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} % 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_Power
0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} ** 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyObject_RichCompare
0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} ?= 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}

输入如下:

rand0m.check('11223344aabbccddeeffeeffaaccddee')

我们可以拿到Log Trace

0x124AC252FFCF = 0x3FFFFFFFFFFFFFFF % 0x1FFE26F569F0
.....此处省略几十行
0x8F154AFD = 0x11223344 ^ 0x9E3779B9
0x12223440 = 0x112233440 & 0xFA3AFFFF
0x12223441 = 0x12223440 + 0x1
0x2268011E2A9 ** 0x40010001
0x13C501CC = 0xEF90A60E6D9E2A9 % 0xFFFFFFFD
0x12223441 ?= 0x52287F38

INT3 breakpoint at python312.00007FF826A9A862!
0x27FE60B7 ?= 0x98D24B3A


INT3 breakpoint at python312.00007FF826A9A862!
0x348CB564 = 0xAABBCCDD ^ 0x9E3779B9
0xAA38CDD0 = 0xAABBCCDD0 & 0xFA3AFFFF
0xAA38CDDA = 0xAA38CDD0 + 0xA
0x100069196 ** 0x40010001
0x0 = 0x0 % 0xFFFFFFFD
0xAA38CDDA ?= 0x4A30F74D

INT3 breakpoint at python312.00007FF826A9A862!
0x2B356987 ?= 0xE0F1DB77


INT3 breakpoint at python312.00007FF826A9A862!
0x70C89746 = 0xEEFFEEFF ^ 0x9E3779B9
0xEA3AEFF0 = 0xEEFFEEFF0 & 0xFA3AFFFF
0xEA3AEFFE = 0xEA3AEFF0 + 0xE
0x1000E1912 ** 0x40010001
0x0 = 0x0 % 0xFFFFFFFD
0xEA3AEFFE ?= 0x423A1268

INT3 breakpoint at python312.00007FF826A9A862!
0x81AC0CF0 ?= 0xADF38403


INT3 breakpoint at python312.00007FF826A9A862!
0x34FBA457 = 0xAACCDDEE ^ 0x9E3779B9
0xA808DEE0 = 0xAACCDDEE0 & 0xFA3AFFFF
0xA808DEEA = 0xA808DEE0 + 0xA
0xC0069F74 ** 0x40010001
0x0 = 0x0 % 0xFFFFFFFD
0xA808DEEA ?= 0x88108807
INT3 breakpoint at python312.00007FF826A9A862!
0x61FF12D1 ?= 0xD8499BB6
INT3 breakpoint at python312.00007FF826A9A862!
...后面没用了,不看了

我们显然可以观察到,对于每个加密后的数据有两组判断,log中具有断点的原因是,如果第一组判断不成立,那么第二组判断不会发生,所以我断下来,手动把PyFalseObject改为了PyTrueObject,让程序以为是正确的。
接下来就是分析,可见一组数据拆成了两部分进行加密,而这两部分都会破坏数据完整性。比如说第一部分异或了一个TEA常量,来让别人感觉是TEA,然后AND了一个 0xFA3AFFFF,显然丢失了很多比特的信息。
第二部分是一个** 0x10001 然后对0xfffffffd取余,很容易让我们想到RSA加密算法,然后我们就可以对N进行分解:
2024-12-15T08:30:26.png

随后就可以写出RSA加密解密函数,把这些参量都算出来。

def rsa_decrypt(x):
    N = 0xfffffffd
    p = 9241
    q = 464773
    assert p * q == N
    phi = (p-1) * (q-1)
    e = 0x10001
    # c = (m ** e) % N
    d = pow(e, -1, phi)
    return pow(x, d, N)

def rsa_encrypt(x):
    N = 0xfffffffd
    e = 0x10001
    return pow(x, e, N)

我们可以注意另一个加密,他对于我们的输入进行一同操作,获取到的结果,如0x*123,我们发现123是原先的低32位,最低4位其实是ROL的结果,这个我们不需要关心,因为RSA那边可以让我们获取到原先数字的高22位,而123可以让我们获取到原先数字的低12位,而我们只需要低11位,所以我们就有思路了:

((rsa_decrypt(enc2) << 11) ^ 0x9E3779B9) & 0xfffff800 来获取高22位
(a >> 4) & 0x7ff 来获取低11位
然后把上面两部分进行拼接,就是整个结果。

所以我们的EXP就是:

def rsa_decrypt(x):
    N = 0xfffffffd
    p = 9241
    q = 464773
    assert p * q == N
    phi = (p-1) * (q-1)
    e = 0x10001
    # c = (m ** e) % N
    d = pow(e, -1, phi)
    return pow(x, d, N)

def rsa_encrypt(x):
    N = 0xfffffffd
    e = 0x10001
    return pow(x, e, N)

enc_list = [(0x52287F38, 0x98D24B3A), 
            (0x4A30F74D, 0xE0F1DB77), 
            (0x423A1268, 0xADF38403), 
            (0x88108807, 0xD8499BB6)]
flag = ''
for i in enc_list:
    a, b = i
    b = rsa_decrypt(b) << 11
    b ^= 0x9E3779B9
    b &= 0xfffff800
    a = (a >> 4) & 0x7ff
    s = a | b
    flag += hex(s)[2:]

print(f"flag{{{flag}}}")
# flag{813a97f3d4b34f74802ba12678950880}

Cython

拿到exe文件,我们先使用 pyinstextractor 来解包,解包出来之后,有一个test1.pyc,一个ez.xx.pyd
显然pyc是程序IO逻辑部分,ez是加密算法部分。
我们反编译pyc可以得到如下结果:

# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: test1.py
# Bytecode version: 3.11a7e (3495)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)

import ez
flag = input('请输入flag:')
flag1 = list(flag)
value = []
b = 0
ck = 0
if len(flag1) == 24:
    for i in range(0, len(flag1), 4):
        b = ord(flag1[i]) 3 * (ord(flag1[i]) 3 * 24, ord(flag1, i[1]) 3) + ord(flag1, i[2]) 3 * 8 + ord(flag1, i[3])
        value.append(b)
    key = [102, 108, 97, 103]
    flag_encrypt = []
    for i in range(0, 6, 2):
        res = ez.encrypt(value[i], value[i 0], key)
        flag_encrypt.append(res)
    ck = ez.check(flag_encrypt)
    if ck == 3:
        print('yes!!!,you get right flag')
    else:  # inserted
        print('wrong!!!')

可以观察到flag长度24,然后转成了大端序的整数,之后进行了2个一组的加密,我们大概可以猜出来是TEA家族的加密算法,随后程序进行了check。
我们手动import一下这个pyd
help(ez)的内容

Help on module ez:

NAME
    ez

FUNCTIONS
    FormatError(...)
        FormatError([integer]) -> string

        Convert a win32 error code into a string. If the error code is not
        given, the return value of a call to GetLastError() is used.

    POINTER(...)

    addressof(...)
        addressof(C instance) -> integer
        Return the address of the C instance internal buffer

    alignment(...)
        alignment(C type) -> integer
        alignment(C instance) -> integer
        Return the alignment requirements of a C instance

    byref(...)
        byref(C instance[, offset=0]) -> byref-object
        Return a pointer lookalike to a C instance, only usable
        as function argument

    check(flag_encrypt)

    encrypt(V0, V1, key)

    get_errno(...)

    get_last_error(...)

    pointer(...)

    resize(...)
        Resize the memory buffer of a ctypes instance

    set_errno(...)

    set_last_error(...)

    sizeof(...)
        sizeof(C type) -> integer
        sizeof(C instance) -> integer
        Return the size in bytes of a C instance

DATA
    DEFAULT_MODE = 0
    GetLastError = <_FuncPtr object>
    RTLD_GLOBAL = 0
    RTLD_LOCAL = 0
    __test__ = {}
    cdll = <ctypes.LibraryLoader object>
    data = [(3914733448, 1983234354), (342009100, 2529626303), (2587440738...
    #[(3914733448, 1983234354), (342009100, 2529626303), (2587440738, 819204946)]
#(2396885758, 685625361)
    memmove = <CFunctionType object>
    memset = <CFunctionType object>
    oledll = <ctypes.LibraryLoader object>
    pydll = <ctypes.LibraryLoader object>
    pythonapi = <PyDLL 'python dll', handle 7ffde60d0000>
    windll = <ctypes.LibraryLoader object>

FILE
    e:\ctf\ez.pyd

可以看到有个

data = [(3914733448, 1983234354), (342009100, 2529626303), (2587440738, 819204946)] (2396885758, 685625361)]

这应该是我们需要找的加密后的值,所以现在我们的分析点只需要在encrypt中就可以了。
Cython 逆向,pyd里面
x64dbg Hook
由于Python虚拟机的Number都是30bit,所以我经过了如下的处理来还原。

2024-12-15T08:33:10.png

PyNumber_And
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) & ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} & 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_Add
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) + ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} + 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_Xor
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) ^ ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} ^ 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_LShift
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) << ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} << 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_RShift
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) >> ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} >> 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_Reminder
0x{([rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)) % ([rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e))} = 0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} % 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyNumber_Power
0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} ** 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}
PyObject_RichCompare
0x{[rcx+0x18] & 0xffffffff | (([rcx+0x18] >> 0x20) << 0x1e)} ?= 0x{[rdx+0x18] & 0xffffffff | (([rdx+0x18] >> 0x20) << 0x1e)}

输入

ez.encrypt(0xdead, 0xc0de, [0x1122, 0x3344, 0x5566, 0x7788])

然后可以得到trace

0x606F0 = 0xC0DE << 0x3
0x7FF8000303 = 0x1FFE0000C0DE >> 0x6
0x605F3 = 0x3000606F0 ^ 0x300000303
0x20010006C6D1 = 0x1FFE000605F3 + 0x30000C0DE
0x80001122 = 0x0 + 0x80001122
0x6D7F3 = 0x30006C6D1 ^ 0x300001122
0x3DB500 = 0x7B6A0 << 0x3
0x7FF8001EDA = 0x1FFE0007B6A0 >> 0x6
0x26B803DABDA = 0x268803DB500 ^ 0x300001EDA
0x20010045627A = 0x1FFE003DABDA + 0x30007B6A0
0xA8C8C = 0x54646454 >> 0xB
0xD4647576 = 0x54646454 + 0x80001122
0x268D421170C = 0x2688045627A ^ 0x54647576
0xA10EBF50 = 0x5421D7EA << 0x3
0x150875F = 0x5421D7EA >> 0x6
0x2E05E380F = 0x2A10EBF50 ^ 0x4150875F
0x2F4800FF9 = 0x2A05E380F + 0x5421D7EA
0xD4647576 = 0x54646454 + 0x80001122
0x2A0E47A8F = 0x2F4800FF9 ^ 0x54647576
0x7618978 = 0xA0EC312F << 0x3
0x283B0C4 = 0xA0EC312F >> 0x6
0x785E239BC = 0x507618978 ^ 0x28283B0C4
0x5A6CE6AEB = 0x505E239BC + 0xA0EC312F
....此处省略很多行

我们从头开始分析。

l = 0xdead
r = 0xc0de
k = [0x1122, 0x3344, 0x5566, 0x7788]

使用这几个值是因为可以在log中清晰看见。
然后跟着分析

v0 = r << 0x3
v1 = r >> 0x6
v2 = v0 ^ v1
v3 = v2 + r
v4 = v3 ^ k[0]
....

整合一下

v4 = (((r << 0x3) ^ (r >> 0x6)) + r) ^ k[0]
....

看得出来,这是XTEA,完整还原如下

l = 0xdead
r = 0xc0de
l += (((r << 3) ^ (r >> 6)) + r) ^ k[0]
l = 0x7B6A0
r += (((l << 3) ^ (l >> 6)) + l) ^ k[0]

后面的>>0xb,也可以说明问题,就是XTEA的左移右移数被改掉了,delta也被改掉了。
由于是第一轮加密,所以DELTA = SUM = 0x54646454,这一点可以很好从Trace里面看出来,然后我们加密对应一下,但是发现结果并不对,意识到可能是round的问题,我们写一个程序Fuzz一下,拿到round是64,也就是说他把XTEA的轮数魔改成了64,知道了上面的信息,我们就可以解出flag。
EXP

from regadgets.bits import byte2dword, dword2byte, pack_dword, bswap32
from typing import List, Tuple, Union
from ctypes import c_uint32
from struct import unpack
def xtea_decrypt(
    src: Union[Tuple[int, int], bytes, List[int]], key: Union[List[int], bytes], delta: int = 0x9E3779B9, rounds: int = 32
) -> Union[Tuple[int, int], bytes, List[int]]:
    # For bytes src
    if type(src) == bytes:
        result = b''
        for i in pack_dword(byte2dword(src)):
            result += dword2byte(xtea_decrypt(i, key, delta, rounds))
        return result
    # For list src
    elif type(src) == list:
        result = b''
        for i in pack_dword(src):
            result += dword2byte(xtea_decrypt(i, key, delta, rounds))
        return result
    elif type(src) != tuple:
        raise "wrong src type"
    # For bytes key
    if type(key) == bytes:
        key = byte2dword(key)
    elif type(key) != list:
        raise "wrong key type"

    l, r = c_uint32(src[0]), c_uint32(src[1])
    sum = c_uint32(delta * rounds)
    k = [c_uint32(key[0]), c_uint32(key[1]), c_uint32(key[2]), c_uint32(key[3])]
    for _ in range(rounds):
        # modified
        r.value -= (((l.value << 3) ^ (l.value >> 6)) + l.value) ^ (
            sum.value + k[(sum.value >> 11) & 3].value
        )
        sum.value -= delta
        # modified
        l.value -= (((r.value << 3) ^ (r.value >> 6)) + r.value) ^ (
            sum.value + k[sum.value & 3].value
        )
    return (l.value, r.value)

k = [102, 108, 97, 103]
enc = [3914733448, 1983234354, 342009100, 2529626303, 2587440738, 819204946]
dec = dword2byte(byte2dword(xtea_decrypt(enc, key=k, delta=0x54646454, rounds=64), endian='big'))
print(dec)
# b'flag{wYemsWPHCGC0ZRPqds}'

vt (赛后解出)

通过参数传递数据,然后程序会GetCommandline然后检测参数有几个,如果只有一个(用户传入的值),就CreateProcess并附加一个父进程的PID,随后子进程会DebugActiveProcess,通过参数的PID来调试父进程。在此同时,父进程会启动一个线程,循环检测IsDebuggerPresent,如果挂载了上去,则开始WaitDebugEvent。与此同时,子进程开始检测用户输入,正确后会解密flag并且输出(注意,输出的函数是GetProcAddress动态加载,所以直接x-ref不过去)。
载入IDA,很多花指令,关闭IDA。
启动x64dbg动态调试,指定参数,第二个PID随便输。断DebugActiveProcess
2024-12-16T17:46:04.png
修改返回值0->1,让进程以为Debug附加成功。此时子进程才会进入验证输入阶段。
程序有GetThreadContext,会检测当前线程的寄存器,反硬件断点。而且在调试的时候,由于多线程会乱跳线程,所以我们先把其他线程多暂停一次,保证我们调试的线程唯一。
程序通过CreateThread创建新线程,进入输入验证子函数。
2024-12-16T17:48:27.png
经过手动分析可以确定这两个函数分别是strlen和byte2hex。后面有一堆的mov都是局部数组变量的初始化,是一个固定的table,记作table0。我们直接对byte2hex的结果(rax)进行硬件断点,经过测试这边没有检测。可以跟踪到一个地方。
2024-12-16T17:50:17.png
这个地方由于我第一次输入的是1111222233334444,所以它表现为(table0[i] - 8) ^ 0x11,之后通过更改输入到1122才发现是XOR input[i % 2],并且只有这两个字节,后面的程序不读,所以输入是????(4个16进制数,而且由于byte2hex函数只支持将A-F大写字母转换,如果写a-f将被识别成0)。
X64dbg Trace
2024-12-16T17:52:33.png
经过第一步后,程序进入下一阶段,我们硬件断点第一步的结果来追踪。我们发现两个点,一个是>>1,一个是>>1 后 xor 一个常数,显然是类似CRC32的东西。
X64dbg Trace
2024-12-16T17:53:33.png

FFFFFFBC = FFFFFFFF^43
7FFFFFDE = FFFFFFBC >> 1
3FFFFFEF = 7FFFFFDE >> 1
F2477CD7 = (3FFFFFEF >> 1) ^ 0xedb88320
949B3D4B = (F2477CD7 >> 1) ^ 0xedb88320
A7F51D85 = (949B3D4B >> 1) ^ 0xedb88320
BE420DE2 = (A7F51D85 >> 1) ^ 0xedb88320
5F2106F1 = BE420DE2 >> 1
C2280058 = (5F2106F1 >> 1) ^ 0xedb88320
C228009B = C2280058^C3
8CAC836D = (C228009B >> 1) ^ 0xedb88320
ABEEC296 = (8CAC836D >> 1) ^ 0xedb88320
55F7614B = ABEEC296 >> 1
C7433385 = (55F7614B >> 1) ^ 0xedb88320
8E191AE2 = (C7433385 >> 1) ^ 0xedb88320
470C8D71 = 8E191AE2 >> 1
CE3EC598 = (470C8D71 >> 1) ^ 0xedb88320
671F62CC = CE3EC598 >> 1
671F6299 = 671F62CC^55
DE37326C = (671F6299 >> 1) ^ 0xedb88320
6F1B9936 = DE37326C >> 1
378DCC9B = 6F1B9936 >> 1
F67E656D = (378DCC9B >> 1) ^ 0xedb88320
9687B196 = (F67E656D >> 1) ^ 0xedb88320
4B43D8CB = 9687B196 >> 1
C8196F45 = (4B43D8CB >> 1) ^ 0xedb88320
89B43482 = (C8196F45 >> 1) ^ 0xedb88320
89B43442 = 89B43482^C0
44DA1A21 = 89B43442 >> 1
CFD58E30 = (44DA1A21 >> 1) ^ 0xedb88320
67EAC718 = CFD58E30 >> 1
33F5638C = 67EAC718 >> 1
19FAB1C6 = 33F5638C >> 1
CFD58E3 = 19FAB1C6 >> 1
EBC62F51 = (CFD58E3 >> 1) ^ 0xedb88320
985B9488 = (EBC62F51 >> 1) ^ 0xedb88320
985B94A0 = 985B9488^28
4C2DCA50 = 985B94A0 >> 1
2616E528 = 4C2DCA50 >> 1
130B7294 = 2616E528 >> 1
985B94A = 130B7294 >> 1
4C2DCA5 = 985B94A >> 1
EFD9ED72 = (4C2DCA5 >> 1) ^ 0xedb88320
77ECF6B9 = EFD9ED72 >> 1
D64EF87C = (77ECF6B9 >> 1) ^ 0xedb88320
D64EF8BF = D64EF87C^C3
869FFF7F = (D64EF8BF >> 1) ^ 0xedb88320
AEF77C9F = (869FFF7F >> 1) ^ 0xedb88320
BAC33D6F = (AEF77C9F >> 1) ^ 0xedb88320
B0D91D97 = (BAC33D6F >> 1) ^ 0xedb88320
B5D40DEB = (B0D91D97 >> 1) ^ 0xedb88320
B75285D5 = (B5D40DEB >> 1) ^ 0xedb88320
B611C1CA = (B75285D5 >> 1) ^ 0xedb88320
5B08E0E5 = B611C1CA >> 1
5B08E0AA = 5B08E0E5^4F
2D847055 = 5B08E0AA >> 1
FB7ABB0A = (2D847055 >> 1) ^ 0xedb88320
7DBD5D85 = FB7ABB0A >> 1
D3662DE2 = (7DBD5D85 >> 1) ^ 0xedb88320
69B316F1 = D3662DE2 >> 1
D9610858 = (69B316F1 >> 1) ^ 0xedb88320
6CB0842C = D9610858 >> 1
36584216 = 6CB0842C >> 1
365842AF = 36584216^B9
F694A277 = (365842AF >> 1) ^ 0xedb88320
96F2D21B = (F694A277 >> 1) ^ 0xedb88320
A6C1EA2D = (96F2D21B >> 1) ^ 0xedb88320
BED87636 = (A6C1EA2D >> 1) ^ 0xedb88320
5F6C3B1B = BED87636 >> 1
C20E9EAD = (5F6C3B1B >> 1) ^ 0xedb88320
8CBFCC76 = (C20E9EAD >> 1) ^ 0xedb88320
465FE63B = 8CBFCC76 >> 1
465FE67B = 465FE63B^40
CE97701D = (465FE67B >> 1) ^ 0xedb88320
8AF33B2E = (CE97701D >> 1) ^ 0xedb88320
45799D97 = 8AF33B2E >> 1
CF044DEB = (45799D97 >> 1) ^ 0xedb88320
8A3AA5D5 = (CF044DEB >> 1) ^ 0xedb88320
A8A5D1CA = (8A3AA5D5 >> 1) ^ 0xedb88320
5452E8E5 = A8A5D1CA >> 1
C791F752 = (5452E8E5 >> 1) ^ 0xedb88320
C791F7AC = C791F752^FE
63C8FBD6 = C791F7AC >> 1
31E47DEB = 63C8FBD6 >> 1
F54ABDD5 = (31E47DEB >> 1) ^ 0xedb88320
971DDDCA = (F54ABDD5 >> 1) ^ 0xedb88320
4B8EEEE5 = 971DDDCA >> 1
C87FF452 = (4B8EEEE5 >> 1) ^ 0xedb88320
643FFA29 = C87FF452 >> 1
DFA77E34 = (643FFA29 >> 1) ^ 0xedb88320
DFA77E3C = DFA77E34^8
6FD3BF1E = DFA77E3C >> 1
37E9DF8F = 6FD3BF1E >> 1
F64C6CE7 = (37E9DF8F >> 1) ^ 0xedb88320
969EB553 = (F64C6CE7 >> 1) ^ 0xedb88320
A6F7D989 = (969EB553 >> 1) ^ 0xedb88320
BEC36FE4 = (A6F7D989 >> 1) ^ 0xedb88320
5F61B7F2 = BEC36FE4 >> 1
2FB0DBF9 = 5F61B7F2 >> 1
2FB0DB43 = 2FB0DBF9^BA
FA60EE81 = (2FB0DB43 >> 1) ^ 0xedb88320
9088F460 = (FA60EE81 >> 1) ^ 0xedb88320
48447A30 = 9088F460 >> 1
24223D18 = 48447A30 >> 1
12111E8C = 24223D18 >> 1
9088F46 = 12111E8C >> 1
48447A3 = 9088F46 >> 1
EFFAA0F1 = (48447A3 >> 1) ^ 0xedb88320
EFFAA0B0 = EFFAA0F1^41
77FD5058 = EFFAA0B0 >> 1
3BFEA82C = 77FD5058 >> 1
1DFF5416 = 3BFEA82C >> 1
EFFAA0B = 1DFF5416 >> 1
EAC75625 = (EFFAA0B >> 1) ^ 0xedb88320
98DB2832 = (EAC75625 >> 1) ^ 0xedb88320
4C6D9419 = 98DB2832 >> 1
CB8E492C = (4C6D9419 >> 1) ^ 0xedb88320
CB8E499C = CB8E492C^B0
65C724CE = CB8E499C >> 1
32E39267 = 65C724CE >> 1
F4C94A13 = (32E39267 >> 1) ^ 0xedb88320
97DC2629 = (F4C94A13 >> 1) ^ 0xedb88320
A6569034 = (97DC2629 >> 1) ^ 0xedb88320
532B481A = A6569034 >> 1
2995A40D = 532B481A >> 1
F9725126 = (2995A40D >> 1) ^ 0xedb88320
F972510E = F9725126^28
7CB92887 = F972510E >> 1
D3E41763 = (7CB92887 >> 1) ^ 0xedb88320
844A8891 = (D3E41763 >> 1) ^ 0xedb88320
AF9DC768 = (844A8891 >> 1) ^ 0xedb88320
57CEE3B4 = AF9DC768 >> 1
2BE771DA = 57CEE3B4 >> 1
15F3B8ED = 2BE771DA >> 1
E7415F56 = (15F3B8ED >> 1) ^ 0xedb88320
E7415FB5 = E7415F56^E3
9E182CFA = (E7415FB5 >> 1) ^ 0xedb88320
4F0C167D = 9E182CFA >> 1
CA3E881E = (4F0C167D >> 1) ^ 0xedb88320
651F440F = CA3E881E >> 1
DF372127 = (651F440F >> 1) ^ 0xedb88320
822313B3 = (DF372127 >> 1) ^ 0xedb88320
ACA90AF9 = (822313B3 >> 1) ^ 0xedb88320
BBEC065C = (ACA90AF9 >> 1) ^ 0xedb88320
BBEC061D = BBEC065C^41
B04E802E = (BBEC061D >> 1) ^ 0xedb88320
58274017 = B04E802E >> 1
C1AB232B = (58274017 >> 1) ^ 0xedb88320
8D6D12B5 = (C1AB232B >> 1) ^ 0xedb88320
AB0E0A7A = (8D6D12B5 >> 1) ^ 0xedb88320
5587053D = AB0E0A7A >> 1
C77B01BE = (5587053D >> 1) ^ 0xedb88320
63BD80DF = C77B01BE >> 1
63BD8063 = 63BD80DF^BC
DC664311 = (63BD8063 >> 1) ^ 0xedb88320
838BA2A8 = (DC664311 >> 1) ^ 0xedb88320
41C5D154 = 838BA2A8 >> 1
20E2E8AA = 41C5D154 >> 1
10717455 = 20E2E8AA >> 1
E580390A = (10717455 >> 1) ^ 0xedb88320
72C01C85 = E580390A >> 1
D4D88D62 = (72C01C85 >> 1) ^ 0xedb88320
D4D88D21 = D4D88D62^43
87D4C5B0 = (D4D88D21 >> 1) ^ 0xedb88320
43EA62D8 = 87D4C5B0 >> 1
21F5316C = 43EA62D8 >> 1
10FA98B6 = 21F5316C >> 1
87D4C5B = 10FA98B6 >> 1
E986250D = (87D4C5B >> 1) ^ 0xedb88320
997B91A6 = (E986250D >> 1) ^ 0xedb88320
4CBDC8D3 = 997B91A6 >> 1
4CBDC873 = 4CBDC8D3^A0
CBE66719 = (4CBDC873 >> 1) ^ 0xedb88320
884BB0AC = (CBE66719 >> 1) ^ 0xedb88320
4425D856 = 884BB0AC >> 1
2212EC2B = 4425D856 >> 1
FCB1F535 = (2212EC2B >> 1) ^ 0xedb88320
93E079BA = (FCB1F535 >> 1) ^ 0xedb88320
49F03CDD = 93E079BA >> 1
C9409D4E = (49F03CDD >> 1) ^ 0xedb88320
C9409D78 = C9409D4E^36
64A04EBC = C9409D78 >> 1
3250275E = 64A04EBC >> 1
192813AF = 3250275E >> 1
E12C8AF7 = (192813AF >> 1) ^ 0xedb88320
9D2EC65B = (E12C8AF7 >> 1) ^ 0xedb88320
A32FE00D = (9D2EC65B >> 1) ^ 0xedb88320
BC2F7326 = (A32FE00D >> 1) ^ 0xedb88320
5E17B993 = BC2F7326 >> 1
5E17B933 = 5E17B993^A0
C2B35FB9 = (5E17B933 >> 1) ^ 0xedb88320
8CE12CFC = (C2B35FB9 >> 1) ^ 0xedb88320
4670967E = 8CE12CFC >> 1
23384B3F = 4670967E >> 1
FC24A6BF = (23384B3F >> 1) ^ 0xedb88320
93AAD07F = (FC24A6BF >> 1) ^ 0xedb88320
A46DEB1F = (93AAD07F >> 1) ^ 0xedb88320
BF8E76AF = (A46DEB1F >> 1) ^ 0xedb88320
BF8E7698 = BF8E76AF^37
5FC73B4C = BF8E7698 >> 1
2FE39DA6 = 5FC73B4C >> 1
17F1CED3 = 2FE39DA6 >> 1
E6406449 = (17F1CED3 >> 1) ^ 0xedb88320
9E98B104 = (E6406449 >> 1) ^ 0xedb88320
4F4C5882 = 9E98B104 >> 1
27A62C41 = 4F4C5882 >> 1
FE6B9500 = (27A62C41 >> 1) ^ 0xedb88320
FE6B95C5 = FE6B9500^C5
928D49C2 = (FE6B95C5 >> 1) ^ 0xedb88320
4946A4E1 = 928D49C2 >> 1
C91BD150 = (4946A4E1 >> 1) ^ 0xedb88320
648DE8A8 = C91BD150 >> 1
3246F454 = 648DE8A8 >> 1
19237A2A = 3246F454 >> 1
C91BD15 = 19237A2A >> 1
EBF05DAA = (C91BD15 >> 1) ^ 0xedb88320
EBF05DE8 = EBF05DAA^42
75F82EF4 = EBF05DE8 >> 1
3AFC177A = 75F82EF4 >> 1
1D7E0BBD = 3AFC177A >> 1
E30786FE = (1D7E0BBD >> 1) ^ 0xedb88320
7183C37F = E30786FE >> 1
D579629F = (7183C37F >> 1) ^ 0xedb88320
8704326F = (D579629F >> 1) ^ 0xedb88320
AE3A9A17 = (8704326F >> 1) ^ 0xedb88320
AE3A9AB5 = AE3A9A17^A2
BAA5CE7A = (AE3A9AB5 >> 1) ^ 0xedb88320
5D52E73D = BAA5CE7A >> 1
C311F0BE = (5D52E73D >> 1) ^ 0xedb88320
6188F85F = C311F0BE >> 1
DD7CFF0F = (6188F85F >> 1) ^ 0xedb88320
8306FCA7 = (DD7CFF0F >> 1) ^ 0xedb88320
AC3BFD73 = (8306FCA7 >> 1) ^ 0xedb88320
BBA57D99 = (AC3BFD73 >> 1) ^ 0xedb88320
BBA57DAC = BBA57D99^35
5DD2BED6 = BBA57DAC >> 1
2EE95F6B = 5DD2BED6 >> 1
FACC2C95 = (2EE95F6B >> 1) ^ 0xedb88320
90DE956A = (FACC2C95 >> 1) ^ 0xedb88320
486F4AB5 = 90DE956A >> 1
C98F267A = (486F4AB5 >> 1) ^ 0xedb88320
64C7933D = C98F267A >> 1
DFDB4ABE = (64C7933D >> 1) ^ 0xedb88320
DFDB4A1C = DFDB4ABE^A2
6FEDA50E = DFDB4A1C >> 1
37F6D287 = 6FEDA50E >> 1
F643EA63 = (37F6D287 >> 1) ^ 0xedb88320
96997611 = (F643EA63 >> 1) ^ 0xedb88320
A6F43828 = (96997611 >> 1) ^ 0xedb88320
537A1C14 = A6F43828 >> 1
29BD0E0A = 537A1C14 >> 1
14DE8705 = 29BD0E0A >> 1
14DE8756 = 14DE8705^53
A6F43AB = 14DE8756 >> 1
E88F22F5 = (A6F43AB >> 1) ^ 0xedb88320
99FF125A = (E88F22F5 >> 1) ^ 0xedb88320
4CFF892D = 99FF125A >> 1
CBC747B6 = (4CFF892D >> 1) ^ 0xedb88320
65E3A3DB = CBC747B6 >> 1
DF4952CD = (65E3A3DB >> 1) ^ 0xedb88320
821C2A46 = (DF4952CD >> 1) ^ 0xedb88320
821C2AB8 = 821C2A46^FE
410E155C = 821C2AB8 >> 1
20870AAE = 410E155C >> 1
10438557 = 20870AAE >> 1
E599418B = (10438557 >> 1) ^ 0xedb88320
9F7423E5 = (E599418B >> 1) ^ 0xedb88320
A20292D2 = (9F7423E5 >> 1) ^ 0xedb88320
51014969 = A20292D2 >> 1
C5382794 = (51014969 >> 1) ^ 0xedb88320
C53827BC = C5382794^28
629C13DE = C53827BC >> 1
314E09EF = 629C13DE >> 1
F51F87D7 = (314E09EF >> 1) ^ 0xedb88320
973740CB = (F51F87D7 >> 1) ^ 0xedb88320
A6232345 = (973740CB >> 1) ^ 0xedb88320
BEA91282 = (A6232345 >> 1) ^ 0xedb88320
5F548941 = BEA91282 >> 1
C212C780 = (5F548941 >> 1) ^ 0xedb88320
C212C73C = C212C780^BC
6109639E = C212C73C >> 1
3084B1CF = 6109639E >> 1
F5FADBC7 = (3084B1CF >> 1) ^ 0xedb88320
9745EEC3 = (F5FADBC7 >> 1) ^ 0xedb88320
A61A7441 = (9745EEC3 >> 1) ^ 0xedb88320
BEB5B900 = (A61A7441 >> 1) ^ 0xedb88320
5F5ADC80 = BEB5B900 >> 1
2FAD6E40 = 5F5ADC80 >> 1
2FAD6E53 = 2FAD6E40^13
FA6E3409 = (2FAD6E53 >> 1) ^ 0xedb88320
908F9924 = (FA6E3409 >> 1) ^ 0xedb88320
4847CC92 = 908F9924 >> 1
2423E649 = 4847CC92 >> 1
FFA97004 = (2423E649 >> 1) ^ 0xedb88320
7FD4B802 = FFA97004 >> 1
3FEA5C01 = 7FD4B802 >> 1
F24DAD20 = (3FEA5C01 >> 1) ^ 0xedb88320
F24DAD96 = F24DAD20^B6
7926D6CB = F24DAD96 >> 1
D12BE845 = (7926D6CB >> 1) ^ 0xedb88320
852D7702 = (D12BE845 >> 1) ^ 0xedb88320
4296BB81 = 852D7702 >> 1
CCF3DEE0 = (4296BB81 >> 1) ^ 0xedb88320
6679EF70 = CCF3DEE0 >> 1
333CF7B8 = 6679EF70 >> 1
199E7BDC = 333CF7B8 >> 1
199E7BEA = 199E7BDC^36
CCF3DF5 = 199E7BEA >> 1
EBDF1DDA = (CCF3DF5 >> 1) ^ 0xedb88320
75EF8EED = EBDF1DDA >> 1
D74F4456 = (75EF8EED >> 1) ^ 0xedb88320
6BA7A22B = D74F4456 >> 1
D86B5235 = (6BA7A22B >> 1) ^ 0xedb88320
818D2A3A = (D86B5235 >> 1) ^ 0xedb88320
40C6951D = 818D2A3A >> 1
40C695BE = 40C6951D^A3
20634ADF = 40C695BE >> 1
FD89264F = (20634ADF >> 1) ^ 0xedb88320
937C1007 = (FD89264F >> 1) ^ 0xedb88320
A4068B23 = (937C1007 >> 1) ^ 0xedb88320
BFBBC6B1 = (A4068B23 >> 1) ^ 0xedb88320
B2656078 = (BFBBC6B1 >> 1) ^ 0xedb88320
5932B03C = B2656078 >> 1
2C99581E = 5932B03C >> 1
2C99584A = 2C99581E^54
164CAC25 = 2C99584A >> 1
E69ED532 = (164CAC25 >> 1) ^ 0xedb88320
734F6A99 = E69ED532 >> 1
D41F366C = (734F6A99 >> 1) ^ 0xedb88320
6A0F9B36 = D41F366C >> 1
3507CD9B = 6A0F9B36 >> 1
F73B65ED = (3507CD9B >> 1) ^ 0xedb88320
962531D6 = (F73B65ED >> 1) ^ 0xedb88320
96253177 = 962531D6^A1
A6AA1B9B = (96253177 >> 1) ^ 0xedb88320
BEED8EED = (A6AA1B9B >> 1) ^ 0xedb88320
B2CE4456 = (BEED8EED >> 1) ^ 0xedb88320
5967222B = B2CE4456 >> 1
C10B1235 = (5967222B >> 1) ^ 0xedb88320
8D3D0A3A = (C10B1235 >> 1) ^ 0xedb88320
469E851D = 8D3D0A3A >> 1
CEF7C1AE = (469E851D >> 1) ^ 0xedb88320
CEF7C1EE = CEF7C1AE^40
677BE0F7 = CEF7C1EE >> 1
DE05735B = (677BE0F7 >> 1) ^ 0xedb88320
82BA3A8D = (DE05735B >> 1) ^ 0xedb88320
ACE59E66 = (82BA3A8D >> 1) ^ 0xedb88320
5672CF33 = ACE59E66 >> 1
C681E4B9 = (5672CF33 >> 1) ^ 0xedb88320
8EF8717C = (C681E4B9 >> 1) ^ 0xedb88320
477C38BE = 8EF8717C >> 1
477C380F = 477C38BE^B1
CE069F27 = (477C380F >> 1) ^ 0xedb88320
8ABBCCB3 = (CE069F27 >> 1) ^ 0xedb88320
A8E56579 = (8ABBCCB3 >> 1) ^ 0xedb88320
B9CA319C = (A8E56579 >> 1) ^ 0xedb88320
5CE518CE = B9CA319C >> 1
2E728C67 = 5CE518CE >> 1
FA81C513 = (2E728C67 >> 1) ^ 0xedb88320
90F861A9 = (FA81C513 >> 1) ^ 0xedb88320
90F861BA = 90F861A9^13
487C30DD = 90F861BA >> 1
C9869B4E = (487C30DD >> 1) ^ 0xedb88320
64C34DA7 = C9869B4E >> 1
DFD925F3 = (64C34DA7 >> 1) ^ 0xedb88320
825411D9 = (DFD925F3 >> 1) ^ 0xedb88320
AC928BCC = (825411D9 >> 1) ^ 0xedb88320
564945E6 = AC928BCC >> 1
2B24A2F3 = 564945E6 >> 1
2B24A251 = 2B24A2F3^A2
F82AD208 = (2B24A251 >> 1) ^ 0xedb88320
7C156904 = F82AD208 >> 1
3E0AB482 = 7C156904 >> 1
1F055A41 = 3E0AB482 >> 1
E23A2E00 = (1F055A41 >> 1) ^ 0xedb88320
711D1700 = E23A2E00 >> 1
388E8B80 = 711D1700 >> 1
1C4745C0 = 388E8B80 >> 1
1C474595 = 1C4745C0^55
E39B21EA = (1C474595 >> 1) ^ 0xedb88320
71CD90F5 = E39B21EA >> 1
D55E4B5A = (71CD90F5 >> 1) ^ 0xedb88320
6AAF25AD = D55E4B5A >> 1
D8EF11F6 = (6AAF25AD >> 1) ^ 0xedb88320
6C7788FB = D8EF11F6 >> 1
DB83475D = (6C7788FB >> 1) ^ 0xedb88320
8079208E = (DB83475D >> 1) ^ 0xedb88320
8079202D = 8079208E^A3
AD841336 = (8079202D >> 1) ^ 0xedb88320
56C2099B = AD841336 >> 1
C6D987ED = (56C2099B >> 1) ^ 0xedb88320
8ED440D6 = (C6D987ED >> 1) ^ 0xedb88320
476A206B = 8ED440D6 >> 1
CE0D9315 = (476A206B >> 1) ^ 0xedb88320
8ABE4AAA = (CE0D9315 >> 1) ^ 0xedb88320
455F2555 = 8ABE4AAA >> 1
455F2500 = 455F2555^55
22AF9280 = 455F2500 >> 1
1157C940 = 22AF9280 >> 1
8ABE4A0 = 1157C940 >> 1
455F250 = 8ABE4A0 >> 1
22AF928 = 455F250 >> 1
1157C94 = 22AF928 >> 1
8ABE4A = 1157C94 >> 1
455F25 = 8ABE4A >> 1
455F86 = 455F25^A3
22AFC3 = 455F86 >> 1
EDA9D4C1 = (22AFC3 >> 1) ^ 0xedb88320
9B6C6940 = (EDA9D4C1 >> 1) ^ 0xedb88320
4DB634A0 = 9B6C6940 >> 1
26DB1A50 = 4DB634A0 >> 1
136D8D28 = 26DB1A50 >> 1
9B6C694 = 136D8D28 >> 1
4DB634A = 9B6C694 >> 1
4DB631F = 4DB634A^55
EFD532AF = (4DB631F >> 1) ^ 0xedb88320
9A521A77 = (EFD532AF >> 1) ^ 0xedb88320
A0918E1B = (9A521A77 >> 1) ^ 0xedb88320
BDF0442D = (A0918E1B >> 1) ^ 0xedb88320
B340A136 = (BDF0442D >> 1) ^ 0xedb88320
59A0509B = B340A136 >> 1
C168AB6D = (59A0509B >> 1) ^ 0xedb88320
8D0CD696 = (C168AB6D >> 1) ^ 0xedb88320
8D0CD635 = 8D0CD696^A3
AB3EE83A = (8D0CD635 >> 1) ^ 0xedb88320
559F741D = AB3EE83A >> 1
C777392E = (559F741D >> 1) ^ 0xedb88320
63BB9C97 = C777392E >> 1
DC654D6B = (63BB9C97 >> 1) ^ 0xedb88320
838A2595 = (DC654D6B >> 1) ^ 0xedb88320
AC7D91EA = (838A2595 >> 1) ^ 0xedb88320
563EC8F5 = AC7D91EA >> 1

算法抄出来

def crc(n):
    for _ in range(8):
        if n % 2 != 0:
            # print(f"{hex((n >> 1) ^ 0xedb88320)} = ({hex(n)} >> 1) ^ 0xedb88320")
            n = (n >> 1) ^ 0xedb88320
            n &= 0xffffffff
        else:
            # print(f"{hex(n >> 1)} = {hex(n)} >> 1")
            n = n >> 1
            n &= 0xffffffff
    return n

def enc1(a):
    table = bytes.fromhex('5A E9 4C EA 41 E9 66 A3 59 E4 21 A0 58 9A 41 C9 58 A6 5A 8A 2F 8A 2E EF 5B 88 2C 88 4A E4 41 A6 0A 9C 2F 89 4D 8B 59 9B 0A 88 4C 89 4C 89 4C 89')
    enc = [a[i % 2] ^ ((table[i] - 8) & 0xff) for i in range(len(table))]
    # print([hex(i) for i in enc])
    r = 0xffffffff
    for i in enc:
        r ^= i
        r = crc(r)
    r ^= 0xffffffff
    return r

最后我们使用X64dbg条件断点来断最后的数据,然后进行追踪,我们可以跳到一个CMP。
2024-12-16T17:55:35.png
原理是我们的输入减去常数和0比较,然后通过setne设置al,之后是一个混淆后的比较,最后的结果体现在下面的ecx。
2024-12-16T17:56:22.png
这个je,不跳转是EXIT,跳转是正确,解密flag。
第一次到这直接改标志位了,但是flag没输出,应该是用输入来进行解密的。
我们可以看到刚刚的cmp,只要结果是CRC的结果就可以,我们选择BruteForce

for i in range(256):
    for j in range(256):
        if enc1([i, j]) == 0xF703DF16:
            print(hex(i), hex(j))
            break

所以EXP是

def crc(n):
    for _ in range(8):
        if n % 2 != 0:
            # print(f"{hex((n >> 1) ^ 0xedb88320)} = ({hex(n)} >> 1) ^ 0xedb88320")
            n = (n >> 1) ^ 0xedb88320
            n &= 0xffffffff
        else:
            # print(f"{hex(n >> 1)} = {hex(n)} >> 1")
            n = n >> 1
            n &= 0xffffffff
    return n

def enc1(a):
    table = bytes.fromhex('5A E9 4C EA 41 E9 66 A3 59 E4 21 A0 58 9A 41 C9 58 A6 5A 8A 2F 8A 2E EF 5B 88 2C 88 4A E4 41 A6 0A 9C 2F 89 4D 8B 59 9B 0A 88 4C 89 4C 89 4C 89')
    enc = [a[i % 2] ^ ((table[i] - 8) & 0xff) for i in range(len(table))]
    # print([hex(i) for i in enc])
    r = 0xffffffff
    for i in enc:
        r ^= i
        r = crc(r)
    r ^= 0xffffffff
    return r

for i in range(256):
    for j in range(256):
        if enc1([i, j]) == 0xF703DF16:
            print(hex(i), hex(j))
            break
0x79 0xbc

输入79BC就可以解出flag。

顺便分析一下解密flag的地方,先malloc,再memset,然后
解密前:
2024-12-16T17:58:06.png
解密后:
2024-12-16T17:58:22.png
2024-12-16T17:59:00.png
flag{MjExNTY3MzE3NTQzMjI=}

标签: none

添加新评论