首页
社区
课程
招聘
[原创] 看雪 CTF2018 第七题 限定域空间变换
2018-6-29 12:13 2347

[原创] 看雪 CTF2018 第七题 限定域空间变换

HHHso 活跃值
22
2018-6-29 12:13
2347
0x00 业务逻辑与模型抽象
    样例主体框架比较主观,main函数获取长度位16字节的输入key,
存放于全局变量00450B80 Hi_key db 10h dup(?) 处。然后通过
函数Hi_check_if_aK2iK_19xyzm_Ke_eq_Kr校验。校验函数步骤如下:
(1)将输入Hi_key映射为字符集Hi_szMapAI索引,构成初始K0
    0040DA68 Hi_szMapAI db 'abcdefghijklmnopqrstuvwxyz+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
(2)我们这里抽象一种有限域三维模型,
函数通过局部定义的"坐标选择向量"loc_A_dw64_b100h[16][16],经空间有限域Hi_xyzm将K0迭代变换19次得到Ke。
Hi_xyzm定义为全局变量,位于 0040FEF0 处。这里抽象为 char Hi_xyzm[x][y][z],其中x,y,z限定取值范围皆为0~63.
xyzm大小为64*64*64;
(3)最后将得到Ke与全局静态变量Kr(0040FEE0 Hi_Kr)比较,若匹配则映射出成功提示"yourserialisgood".

代码业务逻辑如下
int __cdecl main(int argc,const char**argv,const char**envp)
{
  printf("Only 'a'-'z','A'-'Z','0'-'9' accepted.\n");
  printf("Only 16 chars accepted.\n");
  printf("Serial:");
  scanf_s("%s",Hi_key,17);
  Hi_check_if_aK2iK_19xyzm_Ke_eq_Kr();
  system("PAUSE");
  return 0;
}

int Hi_check_if_aK2iK_19xyzm_Ke_eq_Kr()
{
  signed int loc_j;// ebx
  signed int loc_kidx;// esi
  signed int i;// eax
  int loc_nKsize;// eax
  char*loc_pKn_startPosRef;// ecx
  signed int loc_A_WWIdx;// edi
  char*loc_axes;// eax
  int loc_PosN2;// esi
  int v8;// ecx
  int v9;// ecx
  int v10;// ecx
  signed int loc_i;// eax
  _BYTE*loc_pKn_x;// [esp+Ch] [ebp-258h]
  int loc_WWCntOfKNeed2Test_also_K0_N10h;// [esp+10h] [ebp-254h]
  int loc_2N_nKsize;// [esp+14h] [ebp-250h]
  char loc_xyz[3];// [esp+18h] [ebp-24Ch]
  int loc_nKsize_ai;// [esp+1Ch] [ebp-248h]
  KS loc_k0[20];// [esp+20h] [ebp-244h]
  int loc_A_dw64_b100h[64];// [esp+160h] [ebp-104h]

  loc_j=0;
  loc_A_dw64_b100h[0]=65793;
  loc_A_dw64_b100h[1]=0;
  loc_A_dw64_b100h[2]=0;
  loc_A_dw64_b100h[3]=0;
  loc_A_dw64_b100h[4]=16777217;
  loc_A_dw64_b100h[5]=1;
  loc_A_dw64_b100h[6]=0;
  loc_A_dw64_b100h[7]=0;
  loc_A_dw64_b100h[8]=1;
  loc_A_dw64_b100h[9]=65792;
  loc_A_dw64_b100h[10]=0;
  loc_A_dw64_b100h[11]=0;
  loc_A_dw64_b100h[12]=256;
  loc_A_dw64_b100h[13]=16777472;
  loc_A_dw64_b100h[14]=0;
  loc_A_dw64_b100h[15]=0;
  loc_A_dw64_b100h[16]=256;
  loc_A_dw64_b100h[17]=65537;
  loc_A_dw64_b100h[18]=0;
  loc_A_dw64_b100h[19]=0;
  loc_A_dw64_b100h[20]=16842752;
  loc_A_dw64_b100h[21]=0;
  loc_A_dw64_b100h[22]=1;
  loc_A_dw64_b100h[23]=0;
  loc_A_dw64_b100h[24]=0x10000;
  loc_A_dw64_b100h[25]=1;
  loc_A_dw64_b100h[26]=256;
  loc_A_dw64_b100h[27]=0;
  loc_A_dw64_b100h[28]=0x1000000;
  loc_A_dw64_b100h[29]=0x1000000;
  loc_A_dw64_b100h[30]=0x10000;
  loc_A_dw64_b100h[31]=0;
  loc_A_dw64_b100h[32]=0;
  loc_A_dw64_b100h[33]=256;
  loc_A_dw64_b100h[34]=1;
  loc_A_dw64_b100h[35]=1;
  loc_A_dw64_b100h[36]=0;
  loc_A_dw64_b100h[37]=0x10000;
  loc_A_dw64_b100h[38]=0x1000000;
  loc_A_dw64_b100h[39]=256;
  loc_A_dw64_b100h[40]=0;
  loc_A_dw64_b100h[41]=0x1000000;
  loc_A_dw64_b100h[42]=0;
  loc_A_dw64_b100h[43]=257;
  loc_A_dw64_b100h[44]=0;
  loc_A_dw64_b100h[45]=0;
  loc_A_dw64_b100h[46]=16777472;
  loc_A_dw64_b100h[47]=0x10000;
  loc_A_dw64_b100h[48]=0;
  loc_A_dw64_b100h[49]=0;
  loc_A_dw64_b100h[50]=65537;
  loc_A_dw64_b100h[51]=0x10000;
  loc_A_dw64_b100h[52]=0;
  loc_A_dw64_b100h[53]=0;
  loc_A_dw64_b100h[54]=65792;
  loc_A_dw64_b100h[55]=0x1000000;
  loc_A_dw64_b100h[56]=0;
  loc_A_dw64_b100h[57]=0;
  loc_A_dw64_b100h[58]=0x1000000;
  loc_A_dw64_b100h[59]=16777217;
  loc_A_dw64_b100h[60]=0;
  loc_A_dw64_b100h[61]=0;
  loc_A_dw64_b100h[62]=0;
  loc_A_dw64_b100h[63]=16843008;
  loc_kidx=0;
  do
  {
    for(i=0;;++i)
    {
      if(i>=64)
      {
        printf("input error\n");
        system("PAUSE");
        exit(-1);
      }
      if(Hi_szMapAI[i]==(unsigned __int8)Hi_key[loc_kidx])
        break;
    }
    loc_k0[0].kx[loc_kidx++]=i;
  }
  while(loc_kidx<16);
  printf("\n");
  loc_nKsize=16;
  loc_nKsize_ai=16;
  loc_2N_nKsize=2-(_DWORD)&loc_k0[1];
  do
  {
    loc_pKn_startPosRef=(char*)loc_k0+loc_nKsize;
    loc_pKn_x=(char*)loc_k0+loc_nKsize;
    loc_A_WWIdx=0;
    do
    {
      loc_axes=loc_xyz;
      loc_PosN2=(int)&loc_pKn_startPosRef[loc_2N_nKsize];
      loc_WWCntOfKNeed2Test_also_K0_N10h=4;
      do
      {
        v8=(loc_PosN2-2)%16;
        if(*((_BYTE*)&loc_A_dw64_b100h[loc_A_WWIdx]+v8))
          *loc_axes++=*((_BYTE*)&loc_WWCntOfKNeed2Test_also_K0_N10h+v8+loc_nKsize_ai);
        v9=(loc_PosN2-1)%16;
        if(*((_BYTE*)&loc_A_dw64_b100h[loc_A_WWIdx]+v9))
          *loc_axes++=*((_BYTE*)&loc_WWCntOfKNeed2Test_also_K0_N10h+v9+loc_nKsize_ai);
        if(*((_BYTE*)&loc_A_dw64_b100h[loc_A_WWIdx]+loc_PosN2%16))
          *loc_axes++=*((_BYTE*)&loc_WWCntOfKNeed2Test_also_K0_N10h+loc_PosN2%16+loc_nKsize_ai);
        v10=(loc_PosN2+1)%16;
        if(*((_BYTE*)&loc_A_dw64_b100h[loc_A_WWIdx]+v10))
          *loc_axes++=*((_BYTE*)&loc_WWCntOfKNeed2Test_also_K0_N10h+v10+loc_nKsize_ai);
        loc_PosN2+=4;
        --loc_WWCntOfKNeed2Test_also_K0_N10h;
      }
      while(loc_WWCntOfKNeed2Test_also_K0_N10h);
      *loc_pKn_x=Hi_xyzm[64*((unsigned __int8)loc_xyz[1]+((unsigned __int8)loc_xyz[0]<<6))
                         +(unsigned __int8)loc_xyz[2]];
      loc_A_WWIdx+=4;
      loc_pKn_startPosRef=loc_pKn_x+++1;
    }
    while(loc_A_WWIdx<64);
    loc_2N_nKsize-=16;
    loc_nKsize=loc_nKsize_ai+16;
    loc_nKsize_ai=loc_nKsize;
  }
  while(loc_nKsize<0x140);
  loc_i=0;
  do
  {
    if((unsigned __int8)loc_k0[19].kx[loc_i]!=Hi_Kr[loc_i])
      return printf("serial error\n");
    ++loc_i;
  }
  while(loc_i<16);
  do
    printf("%c",(unsigned __int8)Hi_szMapAI[(unsigned int)(unsigned __int8)loc_k0[9].kx[loc_j++]>>1]);
  while(loc_j<16);
  return printf("\n");
}

0x01 提取数据并抽象模型
    IDA+WINDBG,在校验函数下面完成局部定义的"坐标选择向量"loc_A_dw64_b100h[16][16]初始化处断下,
    00401212 xor     esi, esi
    在断点处执行下属IDAPython脚本,得到"坐标选择向量"loc_A_dw64_b100h[16][16],我们定义为A
#------- ------- ------- ------- ------- ------- -------
A_addr = get_reg_value('ebp')-0x104
for i in xrange(0,0x100):#16*16
  print "0x{:02X}, ".format(Byte(A_addr+i)),
  if (i+1)%16 == 0:
    print ""
    print " ",

#------- ------- ------- ------- ------- ------- -------

A = [
  0x01,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  
  0x01,  0x00,  0x00,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  
  0x01,  0x00,  0x00,  0x00,  0x00,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  
  0x00,  0x01,  0x00,  0x00,  0x00,  0x01,  0x00,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  
  0x00,  0x01,  0x00,  0x00,  0x01,  0x00,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  
  0x00,  0x00,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  
  0x00,  0x00,  0x01,  0x00,  0x01,  0x00,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  
  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  
  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,  
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,  0x00,  0x01,  0x00,  0x01,  0x00,  0x00,  
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,  0x00,  0x01,  0x01,  0x00,  0x00,  
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x00,  0x01,  0x00,  0x00,  0x01,  0x00,  
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x00,  0x01,  0x00,  0x00,  0x00,  0x01,  0x00,  
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x01,  
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x01,  0x00,  0x00,  0x01,  
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x01,  0x01]

同时我们也先dump出有限域空间,因为是全局变量,静态或动态情况下都可以;这里我们加载为mxyz矩阵。
savefile(r'C:\CTF2018\CTF07\mxyz', 0, 0x122FEF0, 64*64*64)
with open(r'C:\CTF2018\CTF07\mxyz','rb') as mxyzf:
  mxyz = list(struct.unpack("<{}B".format(64*64*64),mxyzf.read()))
  
"坐标选择向量"与mxyz的变换原理:
(1)定义输入为k,输出为K,如何从k变换到K?
k = [k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,k11,k12,k13,k14,k15]
K = [K0,K1,K2,K3,K4,K5,K6,K7,K8,K9,K10,K11,K12,K13,K14,K15]
(2)以K0的获取为例:我们取上面A的第0x00行数据,其中0x01的位置,决定了选用的k值
0x01,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00
可见,K0选用k的k0,k1,k2作为坐标,其中从左到右依次赋值给xyz,即x=k0,y=k1,z=k2;于是我们得到
K0 = mxyz[x][y][z] //若将mxyz看作一维数组,则K0 = mxyz[(x<<12)+(y<<6)+z]
(3)同样的机制,我们可以得到K的全部取值,则从k变换到K。
这里我们先假定所有的k到K经过A选出的三个坐标都是从左到右依次赋值给x,y,z作为mxyz的坐标。
实际上k[i]到K[i]选出的三个值,并不都是从左到右依次充当x,y,z的角色,为了简化模型,我们后续再修正。


"坐标选择向量"与mxyz的逆变换:
直觉上这么规律变换,再数学上应该存在有效的逆变换求解K到k的变换过程。
这里我们从k到K的变换过程,结合A的特征,尝试求解逆变换:解决K到k的问题。
若得解,即可从Kr逆变换求解19次得到输入的Ki。在样例中
Kr = [0x14,  0x22,  0x1E,  0x10,  0x38,  0x30,  0x18,  0x10,  0x04,  0x1A,  0x24,  0x08,  0x02,  0x26,  0x38,  0x2A]

(1)我们还是采用之前的定义
k = [k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,k11,k12,k13,k14,k15]
K = [K0,K1,K2,K3,K4,K5,K6,K7,K8,K9,K10,K11,K12,K13,K14,K15]
这里K = Kr作为实测样例,现在求k
直观的解法是mxyz.index(K[0]),即可得到 idx = (x<<12)+(y<<6)+(z),通过简单变换,就可得到x,y,z的值,
对K[0]即得到k0,k1,k2。
通过初步测试,mxyz.count(K[i]),i=1..15,解的个数都有4096个。通过对x,y,z解集的树形分类分析,
x     x     y
 y     z     z
  z     y     x
确定了x,y,z中任意两个,即可确定第三个。
如此,我们可以根据K[i]解集结合A特征,不断缩小解集范围,并最终得到唯一或多个解(实测证明不存在多个解,见后续分析说明)

#mxyz.index(K[i]) >> x,y,z
#由K[i]在有限域空间mxyz的位置,得到坐标
def axes2xyz(axes = 0):
  xs = 64*64
  ys = 64
  zs = 1
  rm = axes
  x = rm / xs
  rm = rm % xs
  y =  rm / ys
  z = rm % ys
  return struct.pack("<3B",x,y,z)

#找出K[i]在有限域空间mxyz的所有4069=64*64个可能位置的坐标集
#坐标集归纳为树结构x->y->z->None or x->-z->xyzstr
def r2xyzt(r=0x14,idx=0):
  global mxyz
  cnt = mxyz.count(r)
  xyzt = {}
  s = 0
  for i in xrange(0,cnt):
    axes = mxyz[s:].index(r)
    xyz = axes2xyz(s+axes)
    if idx == 0:
      pass #xyz=xyz
    elif idx in [1,2,3,4,7,8,9,10,11]:
      xyz = xyz[2] + xyz[0] + xyz[1] 
    else:
      xyz = xyz[1] + xyz[2] + xyz[0]
    if xyz[0] not in xyzt:
      xyzt[xyz[0]]={}
    if xyz[1] not in xyzt[xyz[0]]:
      xyzt[xyz[0]][xyz[1]]={}
    if xyz[2] not in xyzt[xyz[0]][xyz[1]]:
      #xyzt[xyz[0]][xyz[1]][xyz[2]]=xyz
      xyzt[xyz[0]][xyz[1]][xyz[2]]=None
    s = s+axes+1
  return xyzt

#由K得到K[i],i=0..15的解集树组
def k2kets(ke=[]):
  #ke = [0x14,  0x22,  0x1E,  0x10,  0x38,  0x30,  0x18,  0x10,  0x04,  0x1A,  0x24,  0x08,  0x02,  0x26,  0x38,  0x2A]
  kets = []
  #for i in ke:
  for i in xrange(0,ke.__len__()):
    kets.append(r2xyzt(ke[i],i))
    print "r2xyzt({:02X}) ok!".format(ke[i])
  return kets

#通过解集树组,结合A的特征,我们计算找出满足A特征的解。
#如此遍历计算所有解64*64*64种情况,可以检测是否有多解
#若不需要检测证明不存在多解,平均遍历64*64*32次可得到解
def kets2k(kets=None):
  ks = []
  for k0 in kets[0].keys():          #kets[0] >> k0 k1 k2
    for k1 in kets[0][k0].keys():    #枚举 k0 64 种情形, k1 64 种情形
      k2 = kets[0][k0][k1].keys()[0] #由A第0行可知: k0 k1 决定了唯一的k2
      for k3 in kets[1][k0].keys():  #kets[1] >> k3 k4  #由A第1行可知:k0已知,枚举 k3 的 64 种情形
        k4=kets[1][k0][k3].keys()[0] #由A第1行可知: k0 k3 决定了唯一的k4
        k6=kets[4][k1][k4].keys()[0] #kets[4] >> k6 #由A第1行可知: k1 k4 决定了唯一的k6
        k8=kets[5][k2][k3].keys()[0] #kets[5] >> k8
        k5=xz2y(kets[2],k0,k6)[0]    #kets[2] >> k5 if len > 2 raise Exception
        k7=kets[3][k1][k5].keys()[0] #kets[3] >> k7
        k9=kets[6][k2][k4].keys()[0] #kets[6] >> k9
        ka=kets[7][k3][k7].keys()[0] #kets[7] >> ka
        kc=kets[8][k5][k8].keys()[0] #kets[8] >> kc
        kd=kets[10][k7][kc].keys()[0] #kets[10] >> kd
        kb=xz2y(kets[9],k6,kd)[0]    #kets[2] >> k5 if len > 2 raise Exception
        ke1 = kets[11][k9][kb].keys()[0]
        ke2 = kets[12][k8][ka].keys()[0]
        if ke1!=ke2:
          continue
        ke=ke1
        kf1 = kets[13][k9][ka].keys()[0]
        kf2 = kets[14][kb][kc].keys()[0]
        kf3 = kets[15][kd][ke].keys()[0]
        if not ((kf1==kf2) and (kf2==kf3)):
          continue
        kf=kf1
        #print ''.join([k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,ka,kb,kc,kd,ke,kf]).__repr__()
        ks.append([k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,ka,kb,kc,kd,ke,kf])
        return ks #返回唯一解,若移动至下面一行位置,则遍历返回所有可能解,也只有一个,这里减少不必要的遍历计算量
  #return ks

#将Ki转换为输入字符Ka
def k2a(k=[]):
  strs = 'abcdefghijklmnopqrstuvwxyz+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
  return b''.join([strs[ci] for ci in k])

#通过迭代求解我们得到输入的ki
#ke=Kr
ke = [0x14,  0x22,  0x1E,  0x10,  0x38,  0x30,  0x18,  0x10,  0x04,  0x1A,  0x24,  0x08,  0x02,  0x26,  0x38,  0x2A]
for i in xrange(0,19):
  ke = kets2k(k2kets(ke))
  if ke.__len__() > 1:
    break
  ke = [ord(c) for c in ke[0]]
  ln = "ke{}=[".format(i+1)
  for c in ke:
    ln +="0x{:02X}, ".format(c)
  print ln[:-2]+']'


以下为上述代码计算ke=Kr经十九次迭代得到的结果
ke = [0x14,  0x22,  0x1E,  0x10,  0x38,  0x30,  0x18,  0x10,  0x04,  0x1A,  0x24,  0x08,  0x02,  0x26,  0x38,  0x2A]
ke1=[0x0F, 0x0B, 0x07, 0x0B, 0x35, 0x03, 0x19, 0x1F, 0x0B, 0x31, 0x3B, 0x33, 0x03, 0x07, 0x15, 0x37]
ke2=[0x3A, 0x26, 0x00, 0x3A, 0x34, 0x06, 0x2C, 0x3C, 0x0E, 0x1E, 0x0A, 0x26, 0x24, 0x18, 0x3C, 0x18]
ke3=[0x0F, 0x07, 0x0D, 0x15, 0x23, 0x3F, 0x3F, 0x19, 0x11, 0x0D, 0x03, 0x25, 0x37, 0x3B, 0x19, 0x31]
ke4=[0x0C, 0x36, 0x16, 0x06, 0x06, 0x26, 0x04, 0x2E, 0x0C, 0x0C, 0x3A, 0x10, 0x10, 0x16, 0x36, 0x22]
ke5=[0x0F, 0x1F, 0x33, 0x0D, 0x2B, 0x2B, 0x19, 0x19, 0x3F, 0x33, 0x35, 0x2D, 0x27, 0x1B, 0x11, 0x07]
ke6=[0x3A, 0x12, 0x3C, 0x0E, 0x2C, 0x3C, 0x2E, 0x08, 0x1E, 0x22, 0x3C, 0x12, 0x26, 0x18, 0x0E, 0x0E]
ke7=[0x19, 0x2F, 0x03, 0x29, 0x15, 0x03, 0x11, 0x29, 0x15, 0x3F, 0x33, 0x09, 0x1F, 0x1D, 0x23, 0x33]
ke8=[0x38, 0x1E, 0x38, 0x2A, 0x0E, 0x16, 0x1E, 0x2A, 0x16, 0x2C, 0x1A, 0x1E, 0x3E, 0x10, 0x08, 0x28]
ke9=[0x27, 0x3D, 0x25, 0x3F, 0x2D, 0x29, 0x19, 0x21, 0x27, 0x39, 0x33, 0x05, 0x17, 0x13, 0x0D, 0x15]
ke10=[0x30, 0x1C, 0x28, 0x22, 0x24, 0x08, 0x22, 0x10, 0x00, 0x16, 0x10, 0x24, 0x0C, 0x1C, 0x1C, 0x06]
ke11=[0x25, 0x05, 0x1F, 0x2D, 0x27, 0x33, 0x19, 0x0B, 0x01, 0x0D, 0x21, 0x31, 0x15, 0x31, 0x3B, 0x17]
ke12=[0x16, 0x2E, 0x36, 0x10, 0x08, 0x28, 0x02, 0x20, 0x06, 0x00, 0x28, 0x0E, 0x14, 0x0A, 0x04, 0x22]
ke13=[0x35, 0x2D, 0x31, 0x17, 0x3B, 0x1D, 0x29, 0x03, 0x21, 0x0B, 0x0B, 0x3F, 0x05, 0x31, 0x11, 0x1D]
ke14=[0x3E, 0x0A, 0x2A, 0x02, 0x2A, 0x08, 0x24, 0x1E, 0x1E, 0x3A, 0x38, 0x1E, 0x2C, 0x2A, 0x1C, 0x3C]
ke15=[0x13, 0x01, 0x27, 0x39, 0x2F, 0x25, 0x1B, 0x09, 0x2D, 0x13, 0x11, 0x1D, 0x31, 0x0B, 0x37, 0x17]
ke16=[0x2E, 0x22, 0x24, 0x0E, 0x2A, 0x36, 0x00, 0x0E, 0x34, 0x2A, 0x32, 0x00, 0x14, 0x20, 0x14, 0x08]
ke17=[0x21, 0x1F, 0x17, 0x03, 0x27, 0x2B, 0x29, 0x01, 0x15, 0x1F, 0x1B, 0x05, 0x25, 0x39, 0x35, 0x23]
ke18=[0x20, 0x30, 0x32, 0x16, 0x32, 0x12, 0x06, 0x32, 0x3C, 0x1A, 0x16, 0x18, 0x30, 0x22, 0x24, 0x1E]
ke19=[0x11, 0x2B, 0x21, 0x05, 0x3F, 0x01, 0x25, 0x0B, 0x39, 0x13, 0x33, 0x09, 0x3F, 0x39, 0x35, 0x25]
>>> ke19=[0x11, 0x2B, 0x21, 0x05, 0x3F, 0x01, 0x25, 0x0B, 0x39, 0x13, 0x33, 0x09, 0x3F, 0x39, 0x35, 0x25]
>>> k2a(ke19)
'rPFf9bJl3tXj93ZJ'


0x03 从简化模型而来的修正
在 def r2xyzt(r=0x14,idx=0)函数中,增加了下述修正代码。源于A中每行从k中选出的三个坐标并不都是
从左到右依次充当x,y,z的角色,如果是,则不需要加入如下代码。
#------- ------- ------- ------- ------- ------- -------
    if idx == 0:
      pass #xyz=xyz
    elif idx in [1,2,3,4,7,8,9,10,11]:
      xyz = xyz[2] + xyz[0] + xyz[1] 
    else:
      xyz = xyz[1] + xyz[2] + xyz[0]
#------- ------- ------- ------- ------- ------- -------
实际上x,y,z的赋值,依次为搜索A中每行第1次、第2次、第2次出现的位置决定的k值。
而各行开始搜索的位置并不都是从0开始的。在0x00的F5修正源码中,
loc_pKn_startPosRef局部变量指示了每行开始循环搜索的位置,
loc_pKn_startPosRef=loc_pKn_x+++1;每循环搜索完一行,其位置都会递增。
即实际各行开始循环搜索的位置是16*16矩阵A的对角线位置。
如A的第1行(从0行开始)
  k0,    k1,    k2,    k3,    k4,    k5,    k6,    k7,    k8,    k9,    k10,   k11,   k12,   k13,   k14,   k15
  0x01,  0x00,  0x00,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  
则K1由k0,k3,k4 索引mxyz空间得到,但由于该行从k1位置开始循环搜索,所以依次搜到的是k3,k4,k0,即x=k3,y=k4,z=k0,
所以K1=mxyz[k3][k4][k0],而不是修正前的的mxyz[k0][k3][k4]

同理,A的第15行(从0行开始)
  k0,    k1,    k2,    k3,    k4,    k5,    k6,    k7,    k8,    k9,    k10,   k11,   k12,   k13,   k14,   k15
  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x01,  0x01,  0x00,  0x00,  0x01,  
则K1由k11,k12,k15 索引mxyz空间得到,但由于该行从k15位置开始循环搜索,所以依次搜到的是k15,k11,k12,即x=k15,y=k11,z=k12,
所以K1=mxyz[k15][k11][k12],而不是修正前的的mxyz[k11][k12][k15]

由于我们的kets2k函数是针对简化模型建立的,所以必须给予修正。
针对A的第1行。简化模型是 k0->k3->k4,由于x=k3,y=k4,z=k0,即得到x,y,z后,需修正为 z->x->y,这就有了
    elif idx in [1,2,3,4,7,8,9,10,11]:
      xyz = xyz[2] + xyz[0] + xyz[1] 
同理,针对第15行,简化模型是k11->k12->k15,由于x=k15,y=k11,z=k12,即得到x,y,z后,需修正为y->z->x这就有了
    else:
      xyz = xyz[1] + xyz[2] + xyz[0]
#-----------------------

上述计算量还算比较大,本机执行r2xyzt得到K[i]解集树的时间2s内,K长为16,就需32s。
遍历求解k的过程kets2k则需要7s内,即完成依次求逆需要39s,19次需要741=39*19约13分钟。
上述执行过程中可以看到计算进度,就像现实版的爬楼梯,一个阶梯一个阶梯爬,每爬16级一层,要爬完19级还是要费点时间。

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

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