首页
论坛
课程
招聘
[原创]2019看雪CTF总决赛第六题:三道八佛WP
2019-12-19 23:56 3207

[原创]2019看雪CTF总决赛第六题:三道八佛WP

2019-12-19 23:56
3207

2019看雪CTF总决赛第六题:三道八佛WP

此题防护与第三赛季的第10题差不多,加了修改。算法方面就更简单了。
我发现的主要修改在于(不全):一是代码迁移的跳转部分加了一种方法;二是数据地址也是动态计算,并不是以前的ebp寻址。代码解码直接用上次的脚本就能搞定,不过需要稍改下断点,范围。

 

代码解码后发现似乎前面大部分代码都没有涉及到有关输入的算法,只是在最后部分有计算代码。动态调试了下,果然算法只在最后一部分,上次的AES使用的表依然在,只是没用上。其伪代码如下:

  v24 = a1;
  s13_14 = a2->state[13] + (a2->state[14] << 8);
  s9_10 = a2->state[9] + (a2->state[10] << 8);
  s11_12 = (a2->state[12] << 8);
  LOWORD(s11_12) = a2->state[11] + s11_12;
  v4 = s11_12;
  v5 = (s11_12 - s9_10);
  s15_0 = a2->state[15] + (a2->state[0] << 8);
  s5_6 = a2->state[6] << 8;
  LOWORD(s5_6) = a2->state[5] + s5_6;
  v7 = s5_6;
  s1_2 = (a2->state[2] << 8);
  LOWORD(s1_2) = a2->state[1] + s1_2;
  v26 = s1_2;
  s3_4 = a2->state[4] << 8;
  LOWORD(s3_4) = a2->state[3] + s3_4;
  v27 = s3_4;
  v10 = (s1_2 ^ s3_4) & 0xFFFF;
  s7_8 = (a2->state[8] << 8) + a2->state[7];
  LOWORD(s3_4) = ((v7 ^ s7_8) & 0x5555) + (((v7 ^ s7_8) >> 1) & 0x5555);
  v12 = (((s3_4 & 0x3333) + ((s3_4 >> 2) & 0x3333)) & 0xF0F)
      + ((((s3_4 & 0x3333) + ((s3_4 >> 2) & 0x3333)) >> 4) & 0xF0F);
  v13 = (v5 & ~v10 | v10 & (s15_0 + s13_14));
  v30 = v13 ^ v7;
  LOWORD(v30) = __ROL2__(v30, HIBYTE(v12) + v12);
  v14 = (v5 & ~v10 | v10 & (s15_0 + s13_14));
  v15 = v14;
  v25 = __ROL2__(v13 ^ ((a2->state[8] << 8) + a2->state[7]), HIBYTE(v12) + v12);
  v16 = ((v10 * v13 >> (HIBYTE(v12) + v12)) + 24) + 0x42DA59;
  v17 = v16;
  v18 = v16 - 0x42DA59;
  v19 = v5 ^ (v17 - 0x42DA59);
  v20 = v14 | v18;
  v23 = v18 + v4;
  v22 = v15 & v18;
  v21 = v22 | (v19 & v20);
  *&a2->state[10] = v18 + a2->state[9] + (a2->state[10] << 8);
  *&a2->state[4] = v19 + s15_0;
  *&a2->state[2] = v26 ^ v21;
  *&a2->state[12] = v25;
  *&a2->state[6] = s13_14 - v19;
  *&a2->state[8] = v23;
  *a2->state = v27 ^ v21;
  *&a2->state[14] = v30;
  *&a2->xbox[220] = v27 ^ v21;
  *&a2->subkey[2][4] = v30;
  *&a2->xbox[176] = v22;
  *&a2->subkey[1][8] = v23;
  *&a2->subkey[5][12] = v24;
  check_4FF3DE();

算法用python模拟如下:

  serial = '5E2BA658A0E9C5F1B52C4C3C4C5C161C'.decode('hex') #BE1C6CB1F1616083
  name = 'BE1C6CB1F1616083'
  s = struct.unpack('H'*8,serial[1:]+serial[0])
  v10 = s[0] ^ s[1]
  v5 = (s[5] - s[4])&0xffff
  v13 = (v5 & ~v10 | v10 & (s[7] + s[6]))  

  tmp = ((s[2]^s[3]) & 0x5555) + (((s[2]^s[3]) >> 1) & 0x5555)
  v12 = ((((tmp & 0x3333) + ((tmp >> 2) & 0x3333)) & 0xF0F) + ((((tmp & 0x3333) + ((tmp >> 2) & 0x3333)) >> 4) & 0xF0F))&0xffff
  bits = ((v12&0xff) + (v12 >> 8))&0xff

  v16 = (((v10 * v13) >> bits) + 24)
  v19 = v5 ^ v16
  v20 = v13 | v16
  v23 = (v16 + s[5])&0xffff
  v22 = v13 & v16
  v21 = (v22 | (v19 & v20))&0xffff
  n = [0]*8

  n[0] = s[1] ^ v21
  n[1] = s[0] ^ v21
  n[2] = (v19 + s[7])&0xffff
  n[3] = (s[6] - v19)&0xffff
  n[4] = v23
  n[5] = (v16 + s[4])&0xffff
  n[6] = rol(v13^s[3],bits,16)
  n[7] = rol(v13^s[2],bits,16)
  nn = struct.pack('H'*8,*n)
  assert(nn == name)

反算如下:

# -*- coding:utf-8 -*-
import struct

def rol(num,bit,n):
  return ((num << (bit%n)) | (num >> (n - bit%n)))&0xffff 

def crack():
  s = [0]*8
  name = 'KCTF'+'\x00\x1A\x19\x18\x17\x16\x15\x14\x13\x12\x11\x10' #6CCDE9D2EC1D469DC67C647E66B4C565
  n = struct.unpack('H'*8,name)
  v10 = n[0] ^ n[1]
  v5 = (n[4] - n[5])&0xffff
  v13 = (v5 & ~v10 | v10 & (n[2] + n[3]))  
  x = n[6] ^ n[7]
  bits = 0
  for i in range(0x10000):
    tmp = ((i) & 0x5555) + (((i) >> 1) & 0x5555)
    v12 = ((((tmp & 0x3333) + ((tmp >> 2) & 0x3333)) & 0xF0F) + ((((tmp & 0x3333) + ((tmp >> 2) & 0x3333)) >> 4) & 0xF0F))&0xffff
    bits = ((v12&0xff) + (v12 >> 8))&0xff
    if ((i >>(16- bits%16)) | (i << (bits%16))) & 0xffff == x:
      break
  v16 = (((v10 * v13) >> bits) + 24)
  v19 = v5 ^ v16
  v20 = v13 | v16
  v22 = v13 & v16
  v21 = (v22 | (v19 & v20))&0xffff
  s[0] = n[1] ^ v21
  s[1] = n[0] ^ v21
  s[7] = (n[2]-v19)&0xffff
  s[6] = (v19 + n[3])&0xffff
  s[5] = (n[4] - v16)&0xffff
  s[4] = (n[5] - v16)&0xffff
  s[3] = (((n[6] >> (bits%16))|(n[6]<<(16-bits%16))) ^ v13)&0xffff
  s[2] = (((n[7] >> (bits%16))|(n[7]<<(16-bits%16))) ^ v13)&0xffff
  ss = struct.pack('H'*8,*s)
  ss = ss[15]+ss[:15]
  serial = ss.encode('hex').upper()
  test(name,ss)
  print serial

def test(name,serial):
#  serial = '5E2BA658A0E9C5F1B52C4C3C4C5C161C'.decode('hex') #BE1C6CB1F1616083
#  name = 'BE1C6CB1F1616083'
  s = struct.unpack('H'*8,serial[1:]+serial[0])
  v10 = s[0] ^ s[1]
  v5 = (s[5] - s[4])&0xffff
  v13 = (v5 & ~v10 | v10 & (s[7] + s[6]))  

  tmp = ((s[2]^s[3]) & 0x5555) + (((s[2]^s[3]) >> 1) & 0x5555)
  v12 = ((((tmp & 0x3333) + ((tmp >> 2) & 0x3333)) & 0xF0F) + ((((tmp & 0x3333) + ((tmp >> 2) & 0x3333)) >> 4) & 0xF0F))&0xffff
  bits = ((v12&0xff) + (v12 >> 8))&0xff

  v16 = (((v10 * v13) >> bits) + 24)
  v19 = v5 ^ v16
  v20 = v13 | v16
  v23 = (v16 + s[5])&0xffff
  v22 = v13 & v16
  v21 = (v22 | (v19 & v20))&0xffff
  n = [0]*8

  n[0] = s[1] ^ v21
  n[1] = s[0] ^ v21
  n[2] = (v19 + s[7])&0xffff
  n[3] = (s[6] - v19)&0xffff
  n[4] = v23
  n[5] = (v16 + s[4])&0xffff
  n[6] = rol(v13^s[3],bits,16)
  n[7] = rol(v13^s[2],bits,16)
  nn = struct.pack('H'*8,*n)
  assert(nn == name)

def main():
  crack()  
  print 'end.'

if __name__ == '__main__':
  main()

[看雪官方培训] Unicorn Trace还原Ollvm算法!《安卓高级研修班》2021年6月班火热招生!!

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回