首页
社区
课程
招聘
[原创]第三题 七十二疑冢
2018-12-6 23:38 4043

[原创]第三题 七十二疑冢

2018-12-6 23:38
4043

题目逻辑比较清晰,不需要太多逆向工作,main函数逻辑如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int basekey_len; // kr00_4
  char *data_; // edx
  signed int i; // esi
  char *pp; // eax
  char *data_1; // ecx
  signed int ctr_4; // edi
  char basekey[139]; // [esp+10h] [ebp-A0h]
  char v11; // [esp+9Bh] [ebp-15h]
  char plaintext[16]; // [esp+9Ch] [ebp-14h]

  strcpy(
    basekey,
    "“Perfection is achieved not when you have nothing more to add, but when you have nothing left to take away.”--Antoin"
    "e de Saint - Exupery");
  v11 = 0;
  basekey_len = strlen(basekey);
  printf("请输入序列号!");
  printf("////当且仅当回显“序列号输入正确”时才算破解成功\n");
  printf("----------------------------------------------------\n");
  printf("序列号:");
  if ( getinput() )
  {
    printf("\n\nInput invalid!\n\n");
    exit(0);
  }
  data_ = &d1[1];
  i = 0;
  do
  {                                             // genkey
    if ( (unsigned __int8)(1 << (7 - (i & 7))) & (unsigned __int8)unhex[(unsigned int)i >> 3] )// by bit 
    {
      pp = &basekey[i + 1];
      data_1 = data_;
      ctr_4 = 4;
      do
      {
        *(pp - 1) ^= *(data_1 - 1);
        *pp ^= *data_1;
        pp[1] ^= data_1[1];
        pp[2] ^= data_1[2];
        data_1 += 4;
        pp += 4;
        --ctr_4;
      }                                         // xor 16
      while ( ctr_4 );
    }
    ++i;                                        // bit = 0, nothing;
                                                // bit = 1, xor 16 byte;
    data_ += 16;
  }
  while ( i < 72 );                             // 9*8 = 72 bit
  *(_DWORD *)plaintext = 0x7AB392EC;
  *(_DWORD *)&plaintext[4] = 0x565BFB02;
  *(_DWORD *)&plaintext[8] = 0xBF433269;
  *(_DWORD *)&plaintext[12] = 0xE27C8D52;
  encrypt(plaintext, basekey, basekey_len);
  if ( plaintext[14] || plaintext[15] )
    printf("\n\n不对哦~~~\n\n");
  else
    printf("\n\n%s\n\n", plaintext);
  getc();
  getc();
  return 0;
}

逻辑很清晰,拿到9字节的输入后,根据对应的72bit生成key,然后加密已知明文,要求所得密文是“序列号输入正确”。同时可以看到,key虽然长度是138,但在生成的过程中最多只改变前87个字节。

 

加密函数流程也很简单,

void __cdecl encrypt(char *dst, char *src, unsigned int len)
{
  char *p; // eax
  unsigned int i; // edx
  int xor; // edi
  _BYTE *next; // eax
  int idx; // edi
  char *item; // ecx
  signed int v9; // esi
  char v10; // bl
  char v11; // bl

  p = dst;
  i = 0;
  if ( len )
  {
    do
    {
      xor = (unsigned __int8)*p ^ (unsigned __int8)src[i];
      next = p + 1;
      idx = 16 * xor;
      item = &d2[idx + 1];
      v9 = 3;
      do
      {
        v10 = *next ^ *(item - 1);
        item += 5;
        *(next - 1) = v10;
        v11 = next[1] ^ *(item - 5);
        next += 5;
        *(next - 5) = v11;
        *(next - 4) = *(next - 3) ^ *(item - 4);
        *(next - 3) = *(next - 2) ^ *(item - 3);
        --v9;
        *(next - 2) = *(next - 1) ^ *(item - 2);
      }
      while ( v9 );
      p = dst;
      ++i;
      dst[15] = d2[idx + 15];
    }
    while ( i < len );
  }
}

138轮的操作,实际上后面138-87=51轮是固定的。

 

可以用python模拟一下这key生成和加密两步操作,

def genkey(x):
    ret = []
    for i in wtf[:87]:
        ret.append(i)
    bb = x
    for i in range(len(bb)):
        for j in range(16):
            ret[i+j] ^= x[i]*d1[i*16+j]
    return ret

def enc(plain, y, round=138):
    assert len(y) == 138
    ret = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
    for i in range(16):
        ret[i] = plain[i]
    for i in y[:round]:
        idx = ret[0] ^ i
        idx *= 16
        for j in range(15):
            ret[j] = ret[j+1] ^ d2[idx+j]
        ret[15] = d2[idx+15]

v12 = [236, 146, 179, 122, 2, 251, 91, 86, 105, 50, 67, 191, 82, 141, 124, 226]
plain = [236, 146, 179, 122, 2, 251, 91, 86, 105, 50, 67, 191, 82, 141, 124, 226]
wtf = [161, 176, 80, 101, 114, 102, 101, 99, 116, 105, 111, 110, 32, 105, 115, 32, 97, 99, 104, 105, 101, 118, 101, 100, 32, 110, 111, 116, 32, 119, 104, 101, 110, 32, 121, 111, 117, 32, 104, 97, 118, 101, 32, 110, 111, 116, 104, 105, 110, 103, 32, 109, 111, 114, 101, 32, 116, 111, 32, 97, 100, 100, 44, 32, 98, 117, 116, 32, 119, 104, 101, 110, 32, 121, 111, 117, 32, 104, 97, 118, 101, 32, 110, 111, 116, 104, 105, 110, 103, 32, 108, 101, 102, 116, 32, 116, 111, 32, 116, 97, 107, 101, 32, 97, 119, 97, 121, 46, 161, 177, 45, 45, 65, 110, 116, 111, 105, 110, 101, 32, 100, 101, 32, 83, 97, 105, 110, 116, 32, 45, 32, 69, 120, 117, 112, 101, 114, 121]
tail = [110, 103, 32, 108, 101, 102, 116, 32, 116, 111, 32, 116, 97, 107, 101, 32, 97, 119, 97, 121, 46, 161, 177, 45, 45, 65, 110, 116, 111, 105, 110, 101, 32, 100, 101, 32, 83, 97, 105, 110, 116, 32, 45, 32, 69, 120, 117, 112, 101, 114, 121]

def dec(xx):
    g = [-1]*87 + tail
    idx = -1
    tmp = []
    for i in xx:
        tmp.append(i)

    for i in range(len(g)):
        tt = tmp[15]
        for j in range(len(d2)):
            if j % 16 == 15 and d2[j] == tt:
                idx = j - 15 
        assert idx != -1

        for k in range(15):
            tmp[15-k] = tmp[15-k-1] ^ d2[idx+15-k-1]
        tmp[0] = (idx/16) ^ g[137-i]
    return tmp

其中dec可以把后面51轮固定操作倒推掉。

 

要求输出中文,也就是,

In [795]: u'序列号输入正确'.encode('gbk')
Out[795]: '\xd0\xf2\xc1\xd0\xba\xc5\xca\xe4\xc8\xeb\xd5\xfd\xc8\xb7'

In [796]: ans = map(ord, u'序列号输入正确'.encode('gbk')) + [0,0,]

In [797]: ans
Out[797]: [208, 242, 193, 208, 186, 197, 202, 228, 200, 235, 213, 253, 200, 183, 0, 0]

这里有两张表,d1和d2,d1用来生成key,d2用于加密过程。观察d2,其中几列明显有规律,第10、11两列看起来不规律。

 

图片描述

 

整体流程中只有异或操作,不妨看看d2[:,10]是否在GF(2)上线性。

sage: a = []
sage: b = []
sage: c = []
sage: for i in range(256):
....:     tmp = [1&(d2[i*16+10]>>j) for j in range(8)]
....:     a.append([1&(i>>j) for j in range(8)])
....:     c.append(tmp)
....:
sage: aa = matrix(GF(2), a)
sage: cc = matrix(GF(2), c)
sage: bb = aa.solve_right(cc)
sage: bb

[0 0 1 0 1 0 0 0]
[0 0 0 1 0 1 0 0]
[0 0 0 0 1 0 1 0]
[0 0 0 0 0 1 0 1]
[0 0 0 0 0 0 1 0]
[1 0 0 0 0 0 0 1]
[0 1 0 0 0 0 0 0]
[0 0 1 0 0 0 0 0]

果然是线性的,11列同理。

 

所以整个流程都是线性的,严格来说明文到密文是线性的,但题目中明文是固定的,这里可以试试看key到密文是不是线性的。只修改key中的固定位置pos的一个bit,看结果中的bit如何变化,如果这种变化跟pos之外的位置上是0是1无关,那么我们就可以得到key和密文的线性关系。

In [718]: b00 = [bits(i) for i in en2(v12, en1([0]*71+[0]), 87)]

In [719]: b01 = [bits(i) for i in en2(v12, en1([0]*71+[1]), 87)]

In [720]: b10 = [bits(i) for i in en2(v12, en1([1]*71+[0]), 87)]

In [721]: b11 = [bits(i) for i in en2(v12, en1([1]*71+[1]), 87)]
...
In [725]: for i in range(16):
     ...:     for j in range(8):
     ...:         if b00[i][j] != b01[i][j]:
     ...:             print (i,j),
     ...:
     ...:
(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (1, 2) (1, 3) (2, 0) (2, 2) (2, 3) (2, 4) (2, 6) (2, 7) (3, 0) (3, 2) (3, 5) (3, 7) (4, 0) (4, 2) (4, 3) (4, 5) (4, 7) (5, 0) (5, 2) (5, 3) (5, 4) (
5, 5) (6, 2) (6, 3) (6, 7) (7, 0) (7, 3) (7, 5) (7, 6) (8, 0) (8, 1) (8, 3) (8, 4) (8, 6) (8, 7) (9, 0) (9, 3) (9, 4) (10, 1) (10, 5) (11, 2) (11, 3) (11, 6) (12, 0) (12, 2) (12, 3) (12, 5)
(12, 6) (13, 1) (13, 3) (13, 5) (13, 7) (14, 0) (14, 1) (14, 2) (14, 3) (14, 6) (15, 1) (15, 6)

In [726]: for i in range(16):
     ...:     for j in range(8):
     ...:         if b10[i][j] != b11[i][j]:
     ...:             print (i,j),
     ...:
     ...:
(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (1, 2) (1, 3) (2, 0) (2, 2) (2, 3) (2, 4) (2, 6) (2, 7) (3, 0) (3, 2) (3, 5) (3, 7) (4, 0) (4, 2) (4, 3) (4, 5) (4, 7) (5, 0) (5, 2) (5, 3) (5, 4) (
5, 5) (6, 2) (6, 3) (6, 7) (7, 0) (7, 3) (7, 5) (7, 6) (8, 0) (8, 1) (8, 3) (8, 4) (8, 6) (8, 7) (9, 0) (9, 3) (9, 4) (10, 1) (10, 5) (11, 2) (11, 3) (11, 6) (12, 0) (12, 2) (12, 3) (12, 5)
(12, 6) (13, 1) (13, 3) (13, 5) (13, 7) (14, 0) (14, 1) (14, 2) (14, 3) (14, 6) (15, 1) (15, 6)

可以看到,虽然前面71个bit不同,但最后一位的bit变化带来的结果变化是一致的。

 

所以现在的加密过程等效于方程AX+B=Y。其中X是key,B是key全为0时的Y,A就是关系阵,dec(ans)可以拿到题目要求的Y,之后解线性方程就可以拿到我们要的X。

 

先拿Y和B,

In [767]: for i in b00:
     ...:     for j in i:
     ...:         print j,',' ,
     ...:
     ...:
     ...:
1 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1
, 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 1 ,
1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 1 , # B
In [770]: ma = de2(ans)
In [771]: mab = [bits(i) for i in ma]
In [772]: mab
Out[772]:
[[0, 1, 0, 0, 0, 1, 1, 1],
 [0, 1, 0, 0, 1, 1, 0, 1],
 [1, 1, 0, 1, 1, 1, 0, 1],
 [0, 1, 0, 0, 0, 1, 0, 0],
 [0, 1, 1, 1, 1, 1, 0, 0],
 [1, 1, 1, 0, 1, 0, 1, 0],
 [0, 1, 0, 0, 0, 1, 0, 0],
 [0, 0, 1, 0, 1, 1, 0, 0],
 [1, 0, 0, 1, 1, 1, 1, 0],
 [1, 1, 1, 0, 1, 1, 0, 0],
 [1, 0, 1, 0, 0, 1, 1, 0],
 [0, 0, 0, 1, 1, 0, 0, 1],
 [0, 0, 1, 1, 1, 0, 1, 0],
 [0, 1, 1, 0, 1, 0, 0, 1],
 [0, 0, 1, 1, 0, 0, 1, 1],
 [0, 0, 1, 0, 1, 0, 1, 1]]

In [773]: for i in mab:
     ...:     for j in i:
     ...:         print j,',' ,
     ...:
     ...:
     ...:
     ...:
0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0
, 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 ,
1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 1 , 1 , # Y

再遍历key的每一个bit,拿到A,

tbl = [0]*72                                                                   
for pos in range(72):                                                          
    tmp = [0]*72                                                               
    tmp[pos] = 1                                                               
    tbl[pos] = []                                                              

    b01 = [bits(i) for i in enc(v12, genkey(tmp), 87)]                         
    for i in range(16):                                                        
        for j in range(8):                                                     
            if b00[i][j] != b01[i][j]:                                         
                tbl[pos].append(i*8+j)                                         

tt = [0]*128
for i in range(72):
    for j in tbl[i]:
        if tt[j] == 0:                                                         
            tt[j] = []                                                         
        tt[j].append(i)                                                        

y = [0]*128                                                                                                   

ttt = [0]*128                                                                  
for i in range(128):                                                           
    ttt[i] = [0]*128                                                           
    for j in tt[i]:
        ttt[i][j] = 1
print ttt

注意这里搞错了矩阵列数,实际上只需要72列,这里弄了成了128*128的,当然其实是无所谓的,多余的都是0。

 

现在就可以算答案了,

sage: b = matrix(GF(2), [1 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 1 , 0
....:  , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1
....:  , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 1 ,])
sage:
sage: mt = matrix(GF(2), ttt)
sage: mt
128 x 128 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries)
sage: y = matrix(GF(2), [0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1
....:  , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0
....:  , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 1 , 1 ])
sage: y-b
1 x 128 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries)
sage: mt.solve_right(((y-b).T))
128 x 1 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries)
sage: print mt.solve_right(((y-b).T)).T.str()
[1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

In [777]: unbits('1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     ...: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0'.replace(' ','')).encode('hex').upper()
Out[777]: 'E7DFE373BFF25B92B600000000000000'

故答案为E7DFE373BFF25B92B6。

 

图片描述


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞5
打赏
分享
最新回复 (1)
雪    币: 264
活跃值: (10)
能力值: ( LV5,RANK:78 )
在线值:
发帖
回帖
粉丝
神枪 2018-12-7 18:05
2
0
分析过程很详细,学习了
游客
登录 | 注册 方可回帖
返回