PC大佬带你玩转游戏安全

寻找关键函数

直接IDA载入,发现静态编译了MFC,无壳,无混淆,没有反调试。 试运行下,一个窗体程序,有两个文本框、checkbox、和按钮。文本框分别输入 UserName 和 Regcode 。 通过 GetDlgItem api找到按键的响应函数,位置 4026F0 ,很明显是主流程。


主流程

函数路径简单明显,通过 SendMessage ,先取 UserName 、 Regcode 和 checkbox 。伪代码如下:

v13 = (CWnd *)this; 

v1 = GetDlgItem(this[8], 1000); memset(name, 0, 0x400u); SendMessageA(v1, 0xDu, 0x400u(LPARAM)name); 

v2 = GetDlgItem(*((HWND *)v13 + 8), 1001); memset(code, 0, 0x400u); SendMessageA(v2, 0xDu, 0x400u, (LPARAM)code); 

v3 = v13; v4 = CWnd::GetDlgItem(v13, 1004); 

flag = SendMessageW(*((HWND *)v4 + 8), 0xF0u, 0, 0) == 1; v13 = (CWnd *)&p_code; p_code.field_14 = 15; 

p_code.length = 0; 

LOBYTE(p_code.field_0) = 0; 

if ( code[0] )

    length1 = strlen(code); 

else

    length1 = 0; 

string_402A70(&p_code, code, length1); 

v26 = 0; 

v10 = 15; 

v9 = 0; 

LOBYTE(p_name.field_0) = 0; 

if ( name[0] )

    length2 = strlen(name); 

else

    length2 = 0; 

string_402A70(&p_name, name, length2); v26 = -1; 

if ( check_routing_405510(

    p_name.field_0,

    p_name.field_4,

    p_name.field_8,

    p_name.field_C,

    v9,

    v10,

    p_code.field_0,

    p_code.field_4,

    p_code.field_8,

    p_code.field_C,

    p_code.length,

    p_code.field_14, flag) )

{

    *(_DWORD *)v16 = 'eR'; 

    v17 = 0; 

    v7 = (const wchar_t *)v16; 

    *(_DWORD *)&v16[4] = 'ig'; 

    *(_DWORD *)&v16[8] = 'ts'; 

    *(_DWORD *)&v16[12] = 're'; 

    *(_DWORD *)&v16[16] = 'S '; 

    *(_DWORD *)&v16[20] = 'cu'; 

    *(_DWORD *)&v16[24] = 'ec'; 

    *(_DWORD *)&v16[28] = 'ss'; 

    *(_DWORD *)&v16[32] = 'C,'; 

    *(_DWORD *)&v16[36] = 'no'; 

    *(_DWORD *)&v16[40] = 'rg'; 

    *(_DWORD *)&v16[44] = 'ta'; 

    *(_DWORD *)&v16[48] = 'lu'; 

    *(_DWORD *)&v16[52] = 'ta'; 

    *(_DWORD *)&v16[56] = 'oi'; 

    *(_DWORD *)&v16[60] = '!n';

// RegisterSuccess,Congratulation!

else {

    *(_DWORD *)v18 = 'eR'; 

    v7 = v18; v19 = 'ig'; 

    v20 = 'ts'; 

    v21 = 're'; 

    v22 = 'F '; 

    v23 = 'ia'; 

    v24 = 'el'; 

    v25 = 'd';

// RegisterFailed

CWnd::SetDlgItemTextW(v3, 1003, v7);

地址为 405510 的函数为主检验函数。


主校验流程

校验的主流程大致过程为:

  • 检查name的有效性。

  • 计算name,得到5个64bit的整数。

  • code先进行base64解码,再进行AES解密,得到32字节数据,前24字节作为3个64bit整数,最后4字节为 00000000 ,剩 下的4字节为 8102 。

  • 对得到的8个64bit整数进行算术校验(中间过程有溢出)。


主流程的主要伪代码如下:

if ( checkname_404F00((struc_1 *)&name) )

    compute_name_405040((int)&name, &v26, &v27, &v28, (int *)&v29, &v30);// name 

    v31 = 0i64; 

    v32 = 0; 

    LOBYTE(v34) = 2; 

    v14 = (const char *) a7; 

    if ( (unsigned int)a12 >= 0x10 

        v14 = (const char *)a7; 

    if ( decode_base64_406080(v14, (int *)&v31) 

       && ((v16 = HIDWORD(v31), v17 = (__m128i *)v31, flag) 

       || (v33 = val_AES_KEY_5A**70, AES_403010(HIDWORD(v31) - v31, v31, (char *)&v33, v15, v31))) 

       && v16 - (_DWORD)v17 == 32 

       && v17[1].m128i_i32[2] == '2018' 

       && !v17[1].m128i_i32[3] )

    {

        v18 = *v17;

        *((_QWORD *)&v33 + 1) = v17[1].m128i_i64[0];   

        v13 = equation_402F20(v26, v27, v28, v29, v30, __PAIR__(_mm_cvtsi128_si32(_mm_srli_si128(v18, 4)), _mm_cvtsi128_si32(v18)), __PAIR__(_mm_cvtsi128_si32(_mm_srli_si128(v18, 12)), _mm_cvtsi128_si32(_mm_srli_si128(v18, 8))), *((__int64 *)&v33 + 1));

    } 

    else 

    { 

        v13 = 0;

    } 

    sub_405740(&v31);

}


校验规则与算法

name的检查与计算

输入值name的检查规则为: 

  • 长度为39。

  • 中间以 # 分隔,通过堆偏移及后续计算,可以得出name分为8个部分,每部分4字节。

  • 除 # 分隔符外,name由hex字符组成,大小写不敏感,计算前全部转成大写


记name的8个部分分别为a0,a1...a7,记结果的输出为b0,b1...b4,name转换成5个大整数的计算公式整理如下:

b0 = (a[0][0]*a[1][0] <<16) + (a[0][1]^a[2][1]) + (a[0][2]%(a[3][2]+1)+1) + a[0][3]/(a[3][3]+1) 


b1 = ((a[1][0]^a[5][0]) <<16) + a[1][1]%(a[6][1]+3) + (a[1][2]/(a[7][2]+1)+5) + a[1][3]+a[0][3] 


b2 = ((a[2][0]/(a[1][0]+3) <<16) ^ (a[2][1]%a[3][1])) + (a[2][2]+a[5][2]+12) + a[2][3]+a[7][3] b3 = (((((a[0][1]^a[2][3]) *(a[3][1]+a[1][3])) &(a[5][2]&a[4][2]))*a[7][3] +b1)*a[6][0]*b0) 


b3 = b3-((b3-b1) %(2*b0)) 


b4 = ((a[4][0]^a[3][0]) <<16) *(a[3][1]%(a[4][1]+2)) + (a[3][2]%(a[4][2]+5)+7) + a[3][3]*a[4][3]


base64解码算法

输入的code先进行base64解码,此处的base64解码算法与标准版有两点改动: 

  • 编解码表改了 

  • 进行查表索引时,加了异或操作 


现用的编码表为:

ZO6Kq79L&CPWvNopzQfghDRSG@di*kAB8rsFewxlm+/u5a^2YtTJUVEn0$HI34y#


AES解密算法

输入的code经过base64解码后进行AES解密。

AES解密算法也是魔改过的,主要改动如下:

  • sbox改动。

  • 密钥扩展时,取key的顺序改动。

  • 取轮密钥时的顺序改动,与扩展密钥的改动对应。应该可以归结为key的变更。

  • 行变换时的改动,及解密时第一轮字节代换与行变换更改了顺序。


AES解密后,检验解密结果为32字节,前24字节为3个整数,后8字节以上文中提到的的规则检查。


方程验证算法

将name及code计算得到的8个整数分别记为b0,b1,b2,b3,b4,c0,c1,c2。


最后的检验计算公式如下(64bit计算,溢出部分不计):

b2 + (b1 + b0 * c0) * c0 == c1 


(b1 - b3) * (b1 - b3) == 4 * (b3 * c0 - (b1 + b0 * c0) * c0) * b0 


b2 + (b1 + b0 * b4 - b3) * b4 == c2

以上公式可写成为:

b2 + (b1 + b0 * c0) * c0 == c1


b0*c0*c0 + (b1 - b3)*c0 +(b1 - b3) * (b1 - b3)/(4*b0) == 0 


b2 + (b1 + b0 * b4 - b3) * b4 == c2

第二个式子就是一个二元一次方程,通过求根公式,可以得到c0的解为 (b3-b1)/(2*b0) 。这个式子明显能得到整数解,在上 面的 b3 的计算公式就能看出:

b3 = b3-((b3-b1) %(2*b0))

其它的计算不在话下,最后整理的python计算公式如下:

c[2] = (b[2] + (b[1] + (b[0] * b[4]) - b[3]) * b[4])&0xffffffffffffffff 


c[0] = ((b[3] - b[1]) / ( 2 * b[0]))&0xffffffffffffffff 


c[1] = (b[2] + (b[1] + (b[0] * c[0])) * c[0])&0xffffffffffffffff

感觉多解还是有的,标准版只是少了AES环节。


测试数据

UserName:1234#5678#90ab#cdef#1234#5678#90ab#cdef Regcode:HxvIC@h4Udf3Y9ti36wmrGVZCG@Q@64ABSv@5ou7BS+=


UserName:1111#1111#1111#1111#1111#1111#1111#1111 Regcode:la9K+2h4UdQH5Pku2Z/PglB/aVrDfe87BSv@5ou7BS+=


注册机说明

注册机使用的是python语言,版本2.7。未使用任何第三方库。


自动化测试脚本

# -*- coding:utf-8 -*-

#Anthor: poyoten @ Chamd5

#Mail: poyoten@hotmail.com

import re


InvSbox = (

      0x9C, 0x6C, 0xF4, 0x32, 0xAE, 0x75, 0x9F, 0x3A, 0x4F, 0x0F, 0xD9, 0x09, 0x5A, 0xC2, 0xCB, 0x61, 

      0x7B, 0x04, 0xE2, 0x25, 0x9D, 0x2E, 0x23, 0x1E, 0xDB, 0x83, 0x5C, 0x6A, 0xB7, 0x5E, 0x**, 0x26, 

      0xBE, 0xE3, 0x15, 0x6F, 0x56, 0x31, 0xFE, 0x0E, 0xBA, 0x00, 0x6D, 0xE0, 0x9E, 0xAF, 0xD0, 0x0A, 

      0x73, 0x7A, 0x78, 0x8E, 0x99, 0x71, 0xE8, 0xA6, 0x63, 0x6E, 0x86, 0x14, 0x0D, 0x97, 0x96, 0x80, 

      0xAD, 0xBD, 0x48, 0x12, 0xB0, 0xEB, 0xCA, 0x6B, 0x52, 0xB4, 0x35, 0xB3, 0x5D, 0x2C, 0x2A, 0xF6, 

      0x9B, 0xE6, 0xA2, 0xD8, 0x89, 0xCE, 0xDD, 0x2B, 0x44, 0x59, 0xF0, 0xF2, 0xA9, 0x22, 0x7F, 0xEC, 

      0x40, 0x8D, 0xA4, 0x5B, 0x8F, 0x0C, 0xB1, 0xAC, 0x46, 0x3F, 0xA3, 0x01, 0xAA, 0x57, 0x1C, 0xF8, 

      0xF1, 0xFF, 0x81, 0x10, 0xBB, 0xDF, 0x60, 0x41, 0xC3, 0xF5, 0xD1, 0x38, 0xD7, 0x47, 0x1F, 0xCC, 

      0xC1, 0x27, 0x82, 0xCD, 0xEE, 0x90, 0x4D, 0x98, 0xD3, 0xBF, 0xE5, 0x19, 0x70, 0x49, 0xB6, 0xE4, 

      0xB9, 0x93, 0x1D, 0x24, 0x8A, 0x88, 0x91, 0xD2, 0x76, 0x17, 0x69, 0x58, 0x68, 0x66, 0x16, 0xB8, 

      0x7E, 0x29, 0x05, 0xC9, 0x3C, 0x21, 0x92, 0x1B, 0xA1, 0xA7, 0xFD, 0x1A, 0xE7, 0x30, 0x33, 0x9A, 

      0x54, 0xFB, 0x08, 0xAB, 0x87, 0xCF, 0xA5, 0x4C, 0x5F, 0xF3, 0xF9, 0x2F, 0x03, 0x39, 0xFC, 0x28, 

      0x8B, 0xC5, 0x42, 0x4A, 0x37, 0x4E, 0x94, 0x95, 0xD4, 0xBC, 0x3E, 0x72, 0xED, 0xEA, 0x74, 0x77, 

      0x3B, 0x45, 0x34, 0x20, 0xC0, 0xC7, 0x8C, 0x0B, 0x67, 0xDC, 0x62, 0xEF, 0x2D, 0x50, 0x13, 0x84, 

      0xE1, 0x07, 0x4B, 0x3D, 0x06, 0x7D, 0xD6, 0x11, 0x64, 0xD5, 0xA0, 0x43, 0xB2, 0xE9, 0x02, 0x65, 

      0xB5, 0x36, 0x18, 0xA8, 0xDE, 0x7C, 0xFA, 0xDA, 0x51, 0xC6, 0x85, 0xF7, 0x53, 0x79, 0xC8, 0x55,

      )

Sbox = (

      0x29, 0x6B, 0xEE, 0xBC, 0x11, 0xA2, 0xE4, 0xE1, 0xB2, 0x0B, 0x2F, 0xD7, 0x65, 0x3C, 0x27, 0x09, 

      0x73, 0xE7, 0x43, 0xDE, 0x3B, 0x22, 0x9E, 0x99, 0xF2, 0x8B, 0xAB, 0xA7, 0x6E, 0x92, 0x17, 0x7E, 

      0xD3, 0xA5, 0x5D, 0x16, 0x93, 0x13, 0x1F, 0x81, 0xBF, 0xA1, 0x4E, 0x57, 0x4D, 0xDC, 0x15, 0xBB, 

      0xAD, 0x25, 0x03, 0xAE, 0xD2, 0x4A, 0xF1, 0x**, 0x7B, 0xBD, 0x07, 0xD0, 0xA4, 0xE3, 0xCA, 0x69, 

      0x60, 0x77, 0xC2, 0xEB, 0x58, 0xD1, 0x68, 0x7D, 0x42, 0x8D, 0xC3, 0xE2, 0xB7, 0x86, 0xC5, 0x08, 

      0xDD, 0xF8, 0x48, 0xFC, 0xB0, 0xFF, 0x24, 0x6D, 0x9B, 0x59, 0x0C, 0x63, 0x1A, 0x4C, 0x1D, 0xB8, 

      0x76, 0x0F, 0xDA, 0x38, 0xE8, 0xEF, 0x9D, 0xD8, 0x9C, 0x9A, 0x1B, 0x47, 0x01, 0x2A, 0x39, 0x23, 

      0x8C, 0x35, 0xCB, 0x30, 0xCE, 0x05, 0x98, 0xCF, 0x32, 0xFD, 0x31, 0x10, 0xF5, 0xE5, 0xA0, 0x5E, 

      0x3F, 0x72, 0x82, 0x19, 0xDF, 0xFA, 0x3A, 0xB4, 0x95, 0x54, 0x94, 0xC0, 0xD6, 0x61, 0x33, 0x64, 

      0x85, 0x96, 0xA6, 0x91, 0xC6, 0xC7, 0x3E, 0x3D, 0x87, 0x34, 0xAF, 0x50, 0x00, 0x14, 0x2C, 0x06, 

      0xEA, 0xA8, 0x52, 0x6A, 0x62, 0xB6, 0x37, 0xA9, 0xF3, 0x5C, 0x6C, 0xB3, 0x67, 0x40, 0x04, 0x2D, 

      0x44, 0x66, 0xEC, 0x4B, 0x49, 0xF0, 0x8E, 0x1C, 0x9F, 0x90, 0x28, 0x74, 0xC9, 0x41, 0x20, 0x89, 

      0xD4, 0x80, 0x0D, 0x78, 0x1E, 0xC1, 0xF9, 0xD5, 0xFE, 0xA3, 0x46, 0x0E, 0x7F, 0x83, 0x55, 0xB5, 

      0x2E, 0x7A, 0x97, 0x88, 0xC8, 0xE9, 0xE6, 0x7C, 0x53, 0x0A, 0xF7, 0x18, 0xD9, 0x56, 0xF4, 0x75, 

      0x2B, 0xE0, 0x12, 0x21, 0x8F, 0x8A, 0x51, 0xAC, 0x36, 0xED, 0xCD, 0x45, 0x5F, 0xCC, 0x84, 0xDB, 

      0x5A, 0x70, 0x5B, 0xB9, 0x02, 0x79, 0x4F, 0xFB, 0x6F, 0xBA, 0xF6, 0xB1, 0xBE, 0xAA, 0x26, 0x71,

      )


# learnt from http://cs.ucsb.edu/~koc/cs178/projects/JT/aes.c

xtime = lambda a: (((a << 1) ^ 0x1B) & 0xFF) if (a & 0x80) else (a << 1)


Rcon = (

    0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,

    0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,

    0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,

    0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39,

)

key_exp = [

            [0x77, 0x65, 0x6c, 0x63], [0x6f, 0x6d, 0x65, 0x67], [0x73, 0x6c, 0x61, 0x62], [0x32, 0x30, 0x31, 0x38], 

            [0x34, 0x72, 0x5b, 0xe3], [0x5b, 0x1f, 0x3e, 0x84], [0x28, 0x73, 0x5f, 0xe6], [0x1a, 0x43, 0x6e, 0xde], 

            [0x1e, 0x26, 0xec, 0x4e], [0x45, 0x39, 0xd2, 0xca], [0x6d, 0x4a, 0x8d, 0x2c], [0x77, 0x09, 0xe3, 0xf2], 

            [0xb7, 0xe7, 0x4a, 0x49], [0xf2, 0xde, 0x98, 0x83], [0x9f, 0x94, 0x15, 0xaf], [0xe8, 0x9d, 0xf6, 0x5d], 

            [0xa6, 0x41, 0x9a, 0xc3], [0x54, 0x9f, 0x02, 0x40], [0xcb, 0x0b, 0x17, 0xef], [0x23, 0x96, 0xe1, 0xb2], 

            [0xf8, 0x41, 0xa1, 0x14], [0xac, 0xde, 0xa3, 0x54], [0x67, 0xd5, 0xb4, 0xbb], [0x44, 0x43, 0x55, 0x09], 

            [0xfb, 0x14, 0xbf, 0xb9], [0x57, 0xca, 0x1c, 0xed], [0x30, 0x1f, 0xa8, 0x56], [0x74, 0x5c, 0xfd, 0x5f], 

            [0x1c, 0x42, 0x1b, 0xf8], [0x4b, 0x88, 0x07, 0x15], [0x7b, 0x97, 0xaf, 0x43], [0x0f, 0xcb, 0x52, 0x1c], 

            [0x6e, 0x59, 0x1f, 0x22], [0x25, 0xd1, 0x18, 0x37], [0x5e, 0x46, 0xb7, 0x74], [0x51, 0x8d, 0xe5, 0x68], 

            [0x9a, 0x37, 0xb4, 0xcb], [0xbf, 0xe6, 0xac, 0xfc], [0xe1, 0xa0, 0x1b, 0x88], [0xb0, 0x2d, 0xfe, 0xe0], 

            [0x51, 0xee, 0x42, 0x39], [0xee, 0x08, 0xee, 0xc5], [0x0f, 0xa8, 0xf5, 0x4d], [0xbf, 0x85, 0x0b, 0xad]

          ]


def text2matrix(text):

    matrix = []

    for i in range(16):

        byte = (text >> (8 * (15 - i))) & 0xFF

        if i % 4 == 0:

            matrix.append([byte])

        else:

            matrix[i / 4].append(byte)

    return matrix


def matrix2text(matrix):

    text = 0

    for i in range(4):

        for j in range(4):

            text |= (matrix[i][j] << (120 - 8 * (4 * i + j)))

    return text



class AES:

    def __init__(self, master_key):

        self.change_key(master_key)


    def change_key(self, master_key):

        self.round_keys = text2matrix(master_key)


        for i in range(4, 4 * 11):

            self.round_keys.append([])

            if i % 4 == 0:                

                byte0 = self.round_keys[i - 1][3] ^ Sbox[self.round_keys[i - 1][3]] ^ self.round_keys[i-4][0] #^ Rcon[i / 4]

                byte1 = self.round_keys[i - 1][2] ^ (Sbox[self.round_keys[i - 1][2]] +1) ^ self.round_keys[i-4][1] 

                byte2 = self.round_keys[i - 1][0] ^ (Sbox[self.round_keys[i - 1][0]] +2) ^ self.round_keys[i-4][2] 

                byte3 = self.round_keys[i - 1][1] ^ (Sbox[self.round_keys[i - 1][1]] +3) ^ self.round_keys[i-4][3] 

                bytes = (byte0<<24 | byte1<<16 | byte2<<8 | byte3)^(byte1&(Rcon[i/4]<<18))

                self.round_keys[i].append((bytes>>24)&0xff)

                self.round_keys[i].append((bytes>>16)&0xff)

                self.round_keys[i].append((bytes>>8)&0xff)

                self.round_keys[i].append(bytes&0xff)


            else:

                for j in range(4):

                    byte = self.round_keys[i - 4][j]^ self.round_keys[i - 1][j]

                    self.round_keys[i].append(byte)


    def encrypt(self, plaintext):

        self.plain_state = text2matrix(plaintext)


        self.__add_round_key(self.plain_state, self.round_keys[:4])


        for i in range(1, 10):

            self.__round_encrypt(self.plain_state, self.round_keys[4 * i : 4 * (i + 1)])

            

        self.__shift_rows(self.plain_state)

        self.__sub_bytes(self.plain_state)        

        self.__add_round_key(self.plain_state, self.round_keys[40:])


        return matrix2text(self.plain_state)


    def decrypt(self, ciphertext):

        self.cipher_state = text2matrix(ciphertext)

        tmp = list(self.cipher_state)

        self.__add_round_key(self.cipher_state, self.round_keys[40:])       

        self.__inv_sub_bytes(self.cipher_state)

        self.__inv_shift_rows(self.cipher_state)

       

        for i in range(9, 0, -1):

            self.__round_decrypt(self.cipher_state, self.round_keys[4 * i : 4 * (i + 1)])


        self.__add_round_key(self.cipher_state, self.round_keys[:4])


        return matrix2text(self.cipher_state)


    def __add_round_key(self, s, k):

        for i in range(4):

          s[i][3] ^= k[i][1]

          s[i][2] ^= k[i][0]

          s[i][1] ^= k[i][2]

          s[i][0] ^= k[i][3]


    def __round_encrypt(self, state_matrix, key_matrix):

        self.__sub_bytes(state_matrix)

        self.__shift_rows(state_matrix)

        self.__mix_columns(state_matrix)

        self.__add_round_key(state_matrix, key_matrix)


    def __round_decrypt(self, state_matrix, key_matrix):

        self.__add_round_key(state_matrix, key_matrix)

        self.__inv_mix_columns(state_matrix)

        self.__inv_shift_rows(state_matrix)

        self.__inv_sub_bytes(state_matrix)


    def __sub_bytes(self, s):

        for i in range(4):

            for j in range(4):

                s[i][j] = Sbox[s[i][j]]


    def __inv_sub_bytes(self, s):

        for i in range(4):

            for j in range(4):

                s[i][j] = InvSbox[s[i][j]]


    def __shift_rows(self, s):

        s[1][0], s[1][1], s[1][2], s[1][3] = s[1][1], s[1][2],s[1][3],s[1][0]

        s[2][0], s[2][1], s[2][2], s[2][3] = s[2][2],s[2][3],s[2][0], s[2][1]

        s[3][0], s[3][1], s[3][2], s[3][3] = s[3][3], s[3][0],s[3][1],s[3][2]


    def __inv_shift_rows(self, s):

        s[1][0], s[1][1], s[1][2], s[1][3] = s[1][3], s[1][0], s[1][1], s[1][2]

        s[2][0], s[2][1], s[2][2], s[2][3] = s[2][2], s[2][3], s[2][0], s[2][1]

        s[3][0], s[3][1], s[3][2], s[3][3] = s[3][1], s[3][2], s[3][3], s[3][0]


    def __mix_single_column(self, a):

        # please see Sec 4.1.2 in The Design of Rijndael

        t = a[0] ^ a[1] ^ a[2] ^ a[3]

        u = a[0]

        a[0] ^= t ^ xtime(a[0] ^ a[1])

        a[1] ^= t ^ xtime(a[1] ^ a[2])

        a[2] ^= t ^ xtime(a[2] ^ a[3])

        a[3] ^= t ^ xtime(a[3] ^ u)


    def __mix_columns(self, s):

        for i in range(4):

            self.__mix_single_column(s[i])


    def __inv_mix_columns(self, s):

        # see Sec 4.1.3 in The Design of Rijndael

        for i in range(4):

            u = xtime(xtime(s[i][0] ^ s[i][2]))

            v = xtime(xtime(s[i][1] ^ s[i][3]))

            s[i][0] ^= u

            s[i][1] ^= v

            s[i][2] ^= u

            s[i][3] ^= v


        self.__mix_columns(s)


def tips():

    tip = '''

            ##########################################n

            #     2018游戏安全技术竞赛 ROUND 1       #n

            #             keymake                    #n

            #     name format: x#x#x#x#x#x#x#x       #n

            #         x is 4-digits hex              #n

            ##########################################n

        '''

    

    print tip.decode('utf-8')


def nameinput():

    name = raw_input('Input name:')

    return name


def namecheck(name):

    print '[*]Checking name...'

    if len(name) != 39:

        print '[*]Name length is wrong'

        return False

    lname = name.split('#')

    pat = '[dA-Fa-f]{4}'

    for i in lname:

        if re.match(pat,i) == None:

            print '[*]Name format is wrong'

            return False

    return True

    

def namecompute(name):

    print '[*]Computing name...'

    lname = name.split('#')

    lname = [list(i.upper()) for i in lname]

    a = [[ord(i) for i in j] for j in lname ]    

    b0 = (a[0][0]*a[1][0] <<16) + (a[0][1]^a[2][1]) + (a[0][2]%(a[3][2]+1)+1) + a[0][3]/(a[3][3]+1)

    b1 = ((a[1][0]^a[5][0]) <<16) + a[1][1]%(a[6][1]+3) + (a[1][2]/(a[7][2]+1)+5) + a[1][3]+a[0][3] 

    b2 = ((a[2][0]/(a[1][0]+3) <<16) ^ (a[2][1]%a[3][1])) + (a[2][2]+a[5][2]+12) + a[2][3]+a[7][3]

    b3 = (((((a[0][1]^a[2][3]) *(a[3][1]+a[1][3])) &(a[5][2]&a[4][2]))*a[7][3] +b1)*a[6][0]*b0)    

    b3 = b3-((b3-b1) %(2*b0))   

    b4 = ((a[4][0]^a[3][0]) <<16) *(a[3][1]%(a[4][1]+2)) + (a[3][2]%(a[4][2]+5)+7) + a[3][3]*a[4][3] 

    b = [b0,b1,b2,b3,b4]

    if (b[3] - b[1]) % ( 2 * b[0]) != 0:

      print '[*]This name can't generate regcode!!!'

      exit(0)

    return b

          

def compcode(b):

    print '[*]Computing regcode...'

    c = [0,0,0]

    c[2] = (b[2] + (b[1] + (b[0] * b[4]) - b[3]) * b[4])&0xffffffffffffffff

    c[0] = ((b[3] - b[1]) / ( 2 * b[0]))&0xffffffffffffffff

    c[1] = (b[2] + (b[1] + (b[0] * c[0])) * c[0])&0xffffffffffffffff

    return c


def genformat(c):

    s = ''

    for i in c:

      tmp = hex(i)[2:].replace('L','').rjust(16,'0').decode('hex')[::-1]

      s += tmp

    s += '8102'+'x00'*4    

    return s

    

def base(code):    

    nell = list(r'ZO6Kq79L&CPWvNopzQfghDRSG@di*kAB8rsFewxlm+/u5a^2YtTJUVEn0$HI34y#')

    msg = list(code)

    bs = ''

    for i in msg:

        bs+="0"*(8-len(bin(ord(i))[2:]))+bin(ord(i))[2:]

    length_b = len(bs)

    times = length_b/6

    c=""

    for i in range(0,times*6,6):

        num = int(bs[i:i+6],2)

        num = num^(num>>3)

        c += nell[num]

    ll = len(bs)%6

    if ll == 2:

        num = (int(bs[-2:],2)<<4) #+ (ord('=')&0xf) 

        num = num^(num>>3)       

        c += nell[num]

        c += '=='

    if ll == 4:

        num = (int(bs[-4:],2)<<2)# + (ord('=')&0x3)

        num = num^(num>>3)

        c += nell[num]

        c += '='    

    return c

    

if __name__ == '__main__':

    tips()    

    key = 'welcomegslab2018'

    name = nameinput()    

    if namecheck(name):

        namenum = namecompute(name)

        code = compcode(namenum)

        code = genformat(code)

        print '[*]Generating final Regcode...'

        cipher = AES(int(key.encode('hex'),16))

        c1 = cipher.encrypt(int(code.encode('hex')[:32],16))

        c2 = cipher.encrypt(int(code.encode('hex')[32:],16))

        fcode = base((hex(c1)[2:].replace('L','').rjust(32,'0')+hex(c2)[2:].replace('L','').rjust(32,'0')).decode('hex'))

        print '[*]final regcode info is:n'+'UserName:'+name+'nRegcode:'+fcode    


本文作者:ChaMd5安全团队

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/71366.html

Tags:
评论  (0)
快来写下你的想法吧!

ChaMd5安全团队

文章数:85 积分: 181

www.chamd5.org 专注解密MD5、Mysql5、SHA1等

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号