首页
社区
课程
招聘
[原创]看雪 2016 CTF 第二十五 camellia
发表于: 2016-12-21 12:05 4158

[原创]看雪 2016 CTF 第二十五 camellia

HHHso 活跃值
22
2016-12-21 12:05
4158

在入口函数0402F80 _WinMain@16定位到窗体显示代码,其中
Hi_DialogFuncf_sub_4030D0为窗体消息处理函数
.text:00403025 push    offset Hi_DialogFuncf_sub_4030D0 ;
.text:0040302A push    0               ; hWndParent
.text:0040302C push    65h             ; lpTemplateName
.text:0040302E push    esi             ; hInstance
.text:0040302F call    ds:DialogBoxParamA

Hi_DialogFuncf_sub_4030D0中,通过一些调用进入注册校验
4030F0 call    Hi_CheckKey_sub_403130

Hi_CheckKey_sub_403130中通过下述代码获取注册码信息,可见注册码长度为0x23
.text:004032F4 mov     eax, Hi_hWnd_dword_42A208
.text:004032F9 push    WM_GETTEXT      ; Msg
.text:004032FB push    eax             ; hWnd
.text:004032FC mov     byte ptr [esp+45Ch+var_320], 0
.text:00403304 call    ds:SendMessageA
.text:0040330A cmp     eax, 23h

紧接着进行普通合法性检测和过滤

Hi_LposArry_dword_428EE0[3] = {0x08,0x11,0x1A}
要求key[0x08]=key[0x11]key[0x1A]="L",并过滤掉
另外要求注册码字符取值范围为 "ABCDEFGHJKMNPQRSTVWXYZ1234567890"和"="
有效字符的ascii值在Tbl100hFF中索引到的值依次为0,1,2,...,0x1E,其中"="为0x20不用
其它字符的ascii值在Tbl100hFF中索引到的值为-1(0xFF),为无效字符。

Tbl100hFF = [
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0x1F, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0xFF, 0xFF, 0xFF, 0x20, 0xFF, 0xFF,
  0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xFF, 0x08, 0x09, 0xFF, 0x0A, 0x0B, 0xFF,
  0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0xFF, 0x11, 0x12, 0x13, 0x14, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]

获取注册码key后,下述调用将key信息转换压缩
004033BA call    Hi_chgpkey_sub_4101F0

转换
idxkey[i] = Tbl100hFF[key[i]];i = 0,0x1F
压缩
idxkey[i]的有效值(不采用的"="对应的0x20除外)最大为5-bits,
压缩即将idxkey总共0x20*5=160位=20字节*(8位/字节)压缩为20字节
定义转换压缩后的注册码信息为五个双字数组 dword cckey[5]

截至其会用camellia对称加密算法对cckey前四个双字组成的0x10字节解密得到cmp1key,
然后比对(cmp1key实际是与'cnbragon@pediyctf2016'的256哈希值高半部分比对),
而cmpkey2 = cckey[4]直接与'cnbragon@pediyctf2016'的256哈希值累积比对。

于是通过得到'cnbragon@pediyctf2016'的256哈希值,
并处理得到累积和对高半部分进行camellia加密即可得到 cckey = camellia_encrypt(cmpkey1)+cmpkey2.
再对cckey解压逆转换,最后进行"L"反过滤补齐,即可得到原注册码

以下代码计算用户"cnbragon@pediyctf2016"的256哈希值存放于var_20C_Hash256_buf200h
.text:004033C7 lea     edx, [esp+44Ch+var_20C_Hash256_buf200h]
.text:004033CE push    edx
.text:004033CF lea     eax, [esp+450h+var_2B0_usernameStr]
.text:004033D6 push    eax             ; lpString
.text:004033D7 call    ds:lstrlenA
.text:004033DD push    eax
.text:004033DE lea     edi, [esp+454h+var_2B0_usernameStr] ; 'cnbragon@pediyctf2016'
.text:004033E5 call    Hi_gen_hash_of_user_sub_402EE0
.text:004033EA add     esp, 8

在4033E5处断下,堆栈可以确定var_20C_Hash256_buf200h的缓冲区地址为0x13F830,
IDA(WINDBG)切换到IDAPython模式,执行以下代码(0x13F830为具体的缓冲区地址)
得到用户名"cnbragon@pediyctf2016"的256位哈希值
#-------
for i in xrange(0,0x20):
  print "0x{:02X},".format(Byte(0x13F830+i)),
  if (i+1)%16 == 0:
    print ""
#-------
上述代码得到字节数组形式
0xB7, 0x98, 0xEF, 0x27, 0xEC, 0x25, 0xCB, 0xBE, 0x0E, 0x8D, 0xF0, 0x21, 0xB8, 0x7A, 0xE4, 0xD3, //低半部分
0xA8, 0x27, 0xF7, 0x4B, 0x09, 0x79, 0x23, 0xC9, 0xC9, 0x6B, 0x97, 0x95, 0xEB, 0xE6, 0x92, 0x38, //高半部分 hash256_HighHalf

#-------
for i in xrange(0,8):
  print "0x{:08X},".format(Dword(0x13F830+i*4)),

print ""
#-------
上述代码得到如下双字形式
0x27EF98B7, 0xBECB25EC, 0x21F08D0E, 0xD3E47AB8, 0x4BF727A8, 0xC9237909, 0x95976BC9, 0x3892E6EB,
#-------
hashwws = [0x27EF98B7, 0xBECB25EC, 0x21F08D0E, 0xD3E47AB8, 0x4BF727A8, 0xC9237909, 0x95976BC9, 0x3892E6EB]

hss = []  #对称相加,hashwws八个双字折叠为4个双字,
hs = c_ulong(0)
for i in xrange(0,4):
  hs.value = hashwws[i] + hashwws[7-i]
  hss.append(hs.value)

hm = c_long(1)  #hashwws八个双字累积
for i in xrange(0,8):
  hm.value *= hashwws[i]

hsm = hss + [hm.value]
[hex(v) for v in hsm]
#得到['0x60827fa2L', '0x546291b5L', '0xeb140617L', '0x1fdba260L', '0x61b45600']
cmpkey2 = 0x61b45600
#-------
对称相加折叠得到的hss在下述代码处用作camellia对称加密算法的key
.text:0040347B lea     eax, [esp+44Ch+var_434_camellia_context]
.text:0040347F lea     edx, [esp+44Ch+var_28C_camellia_key_Buf80h]
.text:00403486 call    Hi_camellia_setup128_sub_401000
下述代码得到hss的字节数组形式
0xA2, 0x7F, 0x82, 0x60, 0xB5, 0x91, 0x62, 0x54, 0x17, 0x06, 0x14, 0xEB, 0x60, 0xA2, 0xDB, 0x1F,

camellia_key = [0xA2, 0x7F, 0x82, 0x60, 0xB5, 0x91, 0x62, 0x54, 0x17, 0x06, 0x14, 0xEB, 0x60, 0xA2, 0xDB, 0x1F]
#-------
def aL2aB(aL = []):
  import struct
  aBstr = ""
  for vL in aL:
    aBstr+=struct.pack("<L",vL)
  for b in aBstr:
    print "0x{:02X},".format(ord(b)),
  print ""

aL2aB(hss)
#-------
前面我们得到用户名"cnbragon@pediyctf2016"的256位哈希值高半部为
cmkey1 = hash256_HighHalf = [0xA8, 0x27, 0xF7, 0x4B, 0x09, 0x79, 0x23, 0xC9, 0xC9, 0x6B, 0x97, 0x95, 0xEB, 0xE6, 0x92, 0x38]

下述代码中是对var_30C_IN_encHashHighHalf 为 cckey 前四个双字,即加密的哈希值高半部解密,
这里我们知道哈希值高半部,需要加密回去
.text:0040348D push    ecx
.text:0040348E lea     esi, [esp+450h+var_320_OUT_decHashHighHalf]
.text:00403495 lea     ecx, [esp+450h+var_30C_IN_encHashHighHalf]
.text:0040349C call    Hi_camellia_decrypt_sub_402760

在样例中我没发现加密函数体,只能另找路数
这个借用看雪学院隔壁MIT学院的FreeBSD中的camellia算法实现,必须声明:版权归原者所有,
e81K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6W2j5W2)9J5k6h3#2A6N6q4)9J5k6h3g2V1N6g2)9J5c8Y4m8W2L8%4m8D9k6g2)9J5c8X3A6Z5j5h3q4K6i4K6u0r3e0h3q4U0c8r3q4@1j5g2)9J5c8X3q4X3M7#2)9J5c8Y4y4A6M7r3u0Q4x3V1k6H3M7X3!0B7k6h3y4@1i4K6u0r3k6Y4u0W2k6h3u0K6k6q4)9J5c8X3S2W2j5h3c8Q4x3V1k6K6P5i4y4Q4x3V1k6U0M7Y4W2H3N6r3!0Q4x3V1k6U0j5h3#2W2L8r3I4A6j5g2)9J5c8X3y4S2L8h3g2D9L8r3W2S2i4K6u0W2j5H3`.`.
e75K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6W2j5W2)9J5k6h3#2A6N6q4)9J5k6h3g2V1N6g2)9J5c8Y4m8W2L8%4m8D9k6g2)9J5c8X3A6Z5j5h3q4K6i4K6u0r3e0h3q4U0c8r3q4@1j5g2)9J5c8X3q4X3M7#2)9J5c8Y4y4A6M7r3u0Q4x3V1k6H3M7X3!0B7k6h3y4@1i4K6u0r3k6Y4u0W2k6h3u0K6k6q4)9J5c8X3S2W2j5h3c8Q4x3V1k6K6P5i4y4Q4x3V1k6U0M7Y4W2H3N6r3!0Q4x3V1k6U0j5h3#2W2L8r3I4A6j5g2)9J5c8X3y4S2L8h3g2D9L8r3W2S2i4K6u0W2K9l9`.`.
8d6K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6W2j5W2)9J5k6h3#2A6N6q4)9J5k6h3g2V1N6g2)9J5c8Y4m8W2L8%4m8D9k6g2)9J5c8X3A6Z5j5h3q4K6i4K6u0r3e0h3q4U0c8r3q4@1j5g2)9J5c8X3q4X3M7#2)9J5c8Y4y4A6M7r3u0Q4x3V1k6H3M7X3!0B7k6h3y4@1i4K6u0r3k6Y4u0W2k6h3u0K6k6q4)9J5c8X3S2W2j5h3c8Q4x3V1k6K6P5i4y4Q4x3V1k6U0M7Y4W2H3N6r3!0Q4x3V1k6U0j5h3#2W2L8r3I4A6j5g2)9J5c8X3y4S2L8h3g2D9L8r3W2S2i4K6u0V1j5i4m8A6i4K6u0W2j5H3`.`.

在Win平台稍稍修正才能用,包括去掉多余的包含,添加以下类型重定义,具体参考附件。
typedef unsigned long uint32_t;
typedef unsigned char uint8_t;
typedef unsigned char u_char;

在camellia-api.c文件最后,我们添加自己的测试功能代码
static u_char camellia_key[16] = {0xA2, 0x7F, 0x82, 0x60, 0xB5, 0x91, 0x62, 0x54, 0x17, 0x06, 0x14, 0xEB, 0x60, 0xA2, 0xDB, 0x1F};
int main(int argc,char* argv[]){
  //u_char inb[16] = {0xB5, 0xF1, 0x9D, 0x6F, 0x9D, 0xFD, 0xAF, 0x8C, 0xEB, 0x7C, 0xF7, 0xED, 0x7C, 0x67, 0x5B, 0xEF};
  u_char inb[16] = {0xA8, 0x27, 0xF7, 0x4B, 0x09, 0x79, 0x23, 0xC9, 0xC9, 0x6B, 0x97, 0x95, 0xEB, 0xE6, 0x92, 0x38};
  //u_char inb[16] = {0xF7, 0x6C, 0x2B, 0x9F, 0x8D, 0x05, 0x6B, 0xFF, 0xF8, 0x88, 0xE7, 0x83, 0x0B, 0x85, 0xE2, 0x8C};
  u_char outb[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  camellia_ctx ctx;
  int i = 0;
  memset(&ctx,0,sizeof(camellia_ctx));
  camellia_set_key(&ctx,(const u_char *)&camellia_key[0],128);
  /*
  camellia_decrypt(&ctx,(const u_char *)&inb[0],(u_char *)&outb[0]);
  for(i=0;i<16;i++){
    printf("%02X ",outb[i]);
  }
  printf("\n");
  */

  camellia_encrypt(&ctx,(const u_char *)&inb[0],(u_char *)&outb[0]);
  for(i=0;i<16;i++){
    printf("0x%02X, ",outb[i]);
  }
  printf("\n");

}

最后通过"cl camellia-api.c camellia.c"在控制台下直接编译执行得到加密结果
0xF7, 0x6C, 0x2B, 0x9F, 0x8D, 0x05, 0x6B, 0xFF, 0xF8, 0x88, 0xE7, 0x83, 0x0B, 0x85, 0xE2, 0x8C,
编译与执行如下(19 means 0x19, is 第25题)
//------- ------- ------- ------- ------- ------- -------
D:\CFT\CTF19>cl camellia-api.c camellia.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

camellia-api.c
camellia.c
Generating Code...
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:camellia-api.exe
camellia-api.obj
camellia.obj

D:\CFT\CTF19>camellia-api.exe
0xF7, 0x6C, 0x2B, 0x9F, 0x8D, 0x05, 0x6B, 0xFF, 0xF8, 0x88, 0xE7, 0x83, 0x0B, 0x85, 0xE2, 0x8C,
//------- ------- ------- ------- ------- ------- -------
即camellia_encrypt(cmpkey1)为 [0xF7, 0x6C, 0x2B, 0x9F, 0x8D, 0x05, 0x6B, 0xFF, 0xF8, 0x88, 0xE7, 0x83, 0x0B, 0x85, 0xE2, 0x8C]
又cmpkey2 = 0x61b45600,cckey = camellia_encrypt(cmpkey1)+cmpkey2
所以 cckey =
0xF7, 0x6C, 0x2B, 0x9F, 0x8D, 0x05, 0x6B, 0xFF, 0xF8, 0x88, 0xE7, 0x83, 0x0B, 0x85, 0xE2, 0x8C, 0x00, 0x56, 0xB4, 0x61

接着我们需要对cckey解压和逆转换
解压直接字节数组和字节位左到右的顺序每五位解压为一个字符索引字节,逆转换直接索引表即可
每五位会解压出8个字符索引,这里我们分为四组进行
0xF7, 0x6C, 0x2B, 0x9F, 0x8D
0x05, 0x6B, 0xFF, 0xF8, 0x88
0xE7, 0x83, 0x0B, 0x85, 0xE2
0x8C, 0x00, 0x56, 0xb4, 0x61
以下是解压逆转换代码python实现,执行下述代码前先将上述 Tbl100hFF矩阵复制到python编译
#------- ------- ------- ------- ------- ------- -------
def parse_byte5(byte5 = None):
  byte_idx = []
  bits5 = c_ubyte(0)
  bits5.value = byte5[0]>>3
  byte_idx.append(bits5.value)
  bits5.value = ((byte5[0]&7)<<2) | (byte5[1]>>6)
  byte_idx.append(bits5.value)
  bits5.value = (byte5[1]>>1)&0x1F
  byte_idx.append(bits5.value)
  bits5.value = ((byte5[1]&1)<<4) | (byte5[2]>>4)
  byte_idx.append(bits5.value)
  bits5.value = ((byte5[2]&0x0F)<<1) | (byte5[3]>>7)
  byte_idx.append(bits5.value)
  bits5.value = (byte5[3]>>2)&0x1F
  byte_idx.append(bits5.value)
  bits5.value = ((byte5[3]&0x3)<<3) | (byte5[4]>>5)
  byte_idx.append(bits5.value)
  bits5.value = byte5[4]&0x1F
  byte_idx.append(bits5.value)
  return b"".join([chr(Tbl100hFF.index(bits5val)) for bits5val in byte_idx])

parse_byte5([0xF7, 0x6C, 0x2B, 0x9F, 0x8D])
parse_byte5([0x05, 0x6B, 0xFF, 0xF8, 0x88])
parse_byte5([0xE7, 0x83, 0x0B, 0x85, 0xE2])
parse_byte5([0x8C, 0x00, 0x56, 0xb4, 0x61])
------- ------- ------- ------- ------- ------- -------
>>> parse_byte5([0xF7, 0x6C, 0x2B, 0x9F, 0x8D])
'981C2H7Q'
>>> parse_byte5([0x05, 0x6B, 0xFF, 0xF8, 0x88])
'AZZ009EJ'
>>> parse_byte5([0xE7, 0x83, 0x0B, 0x85, 0xE2])
'79BT2BSC'
>>> parse_byte5([0x8C, 0x00, 0x56, 0xb4, 0x61])
'VTAFQQDB'
于是我们组合得到"L"过滤后的注册码"981C2H7QAZZ009EJ79BT2BSCVTAFQQDB"
如前面所述,过滤规则要求 key[0x08]=key[0x11]key[0x1A]="L"
于是我们在相应位置插入"L"即可得到完整的注册码
981C2H7QLAZZ009EJL79BT2BSCLVTAFQQDB

如能能把hash256也还原或替换,即可得到相应的针对不同用户名的注册机。
这里以获取用户名"#KeygenMe#LicenseCode_camellia_MIT_2017_pediy"注册码为例
(不在是原来的"cnbragon@pediyctf2016")
#KeygenMe#LicenseCode_camellia_MIT_2017_pediy
IDA(WINDBG)在04033E5 call    Hi_gen_hash_of_user_sub_402EE0断下
WINDBG命令修改用户名和长度信息
eza edi "#KeygenMe#LicenseCode_camellia_MIT_2017_pediy"
ed esp 2d
得到256哈希
0x5A, 0xA1, 0x35, 0xF5, 0xE2, 0xA2, 0x38, 0x5D, 0xEE, 0x70, 0xA5, 0x8E, 0x08, 0x29, 0x4C, 0x13,
0x38, 0xA2, 0x20, 0xBE, 0xFB, 0xE6, 0xA8, 0x22, 0x5A, 0xEB, 0xB6, 0xFA, 0xF6, 0xF1, 0x02, 0x60,
hashwws = [0xF535A15A, 0x5D38A2E2, 0x8EA570EE, 0x134C2908, 0xBE20A238, 0x22A8E6FB, 0xFAB6EB5A, 0x6002F1F6]
得到折叠和与累积
hsm = ['0x55389350L', '0x57ef8e3cL', '0xb14e57e9L', '0xd16ccb40L', '0x74ca8800']
camellia_key = [0x50, 0x93, 0x38, 0x55, 0x3C, 0x8E, 0xEF, 0x57, 0xE9, 0x57, 0x4E, 0xB1, 0x40, 0xCB, 0x6C, 0xD1]
cmkey2 = 0x74ca8800
以折叠和为key加密哈希高半部
hash256_HighHalf = =[0x38, 0xA2, 0x20, 0xBE, 0xFB, 0xE6, 0xA8, 0x22, 0x5A, 0xEB, 0xB6, 0xFA, 0xF6, 0xF1, 0x02, 0x60]
camellia_encrypt(cmpkey1) = [0xA0, 0xC7, 0x8C, 0xC7, 0xAF, 0x5C, 0x97, 0x67, 0x8A, 0xAD, 0x98, 0x8D, 0x8B, 0x2C, 0x98, 0x6F]
对cckey解压逆转换,反过滤"L"
0xA0, 0xC7, 0x8C, 0xC7, 0xAF
0x5C, 0x97, 0x67, 0x8A, 0xAD
0x98, 0x8D, 0x8B, 0x2C, 0x98
0x6F, 0x00, 0x88, 0xCA, 0x74
parse_byte5([0xA0, 0xC7, 0x8C, 0xC7, 0xAF ])
parse_byte5([0x5C, 0x97, 0x67, 0x8A, 0xAD ])
parse_byte5([0x98, 0x8D, 0x8B, 0x2C, 0x98 ])
parse_byte5([0x6F, 0x00, 0x88, 0xCA, 0x74 ])
即可得到注册码用户"#KeygenMe#LicenseCode_camellia_MIT_2017_pediy"的注册码
YDD34V8SLNWN1SCZQLXCG31NE3LQ7AJVWXY

camellia实现附件 CTF19_MIT_FreeBSD_camellia.7z


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 180
活跃值: (82)
能力值: ( LV12,RANK:443 )
在线值:
发帖
回帖
粉丝
2
非常详细,赞!
有个问题怎么看出是camellia算法的?而且这个算法怎么保证是对称的?
我逆推这个算法的时候,地址为401DB0
这个算法中间有个4个或运算,其他的异或都已经逆推出来了,感觉不是可逆的运算
2016-12-23 16:11
0
雪    币: 180
活跃值: (82)
能力值: ( LV12,RANK:443 )
在线值:
发帖
回帖
粉丝
3
看了你上传的附件中的解密算法,难道是因为他的配套矩阵的特殊性,使得或运算逆推的唯一性,神奇了
2016-12-23 16:15
0
游客
登录 | 注册 方可回帖
返回