首页
社区
课程
招聘
[原创]看雪.京东 2018CTF-第七题分析
发表于: 2018-6-29 18:25 2702

[原创]看雪.京东 2018CTF-第七题分析

2018-6-29 18:25
2702
int check()
{
  signed int v0; // ebx
  signed int index; // esi
  signed int i; // eax
  int v3; // eax
  char *v4; // ecx
  signed int v5; // edi
  char *pkey3CharBuf; // eax
  int v7; // esi
  int v8; // ecx
  int v9; // ecx
  int v10; // ecx
  signed int v11; // eax
  char *v13; // [esp+Ch] [ebp-258h]
  int cnt; // [esp+10h] [ebp-254h]
  int v15; // [esp+14h] [ebp-250h]
  char key3CharBuf[3]; // [esp+18h] [ebp-24Ch]
  int v17; // [esp+1Ch] [ebp-248h]
  char inputIndexKey[20][16]; // [esp+20h] [ebp-244h]
  char table[256]; // [esp+160h] [ebp-104h]

  v0 = 0;
  *(_DWORD *)table = 65793;
  *(_DWORD *)&table[4] = 0;
  *(_DWORD *)&table[8] = 0;
  *(_DWORD *)&table[12] = 0;
  *(_DWORD *)&table[16] = 16777217;
  *(_DWORD *)&table[20] = 1;
  *(_DWORD *)&table[24] = 0;
  *(_DWORD *)&table[28] = 0;
  *(_DWORD *)&table[32] = 1;
  *(_DWORD *)&table[36] = 65792;
  *(_DWORD *)&table[40] = 0;
  *(_DWORD *)&table[44] = 0;
  *(_DWORD *)&table[48] = 256;
  *(_DWORD *)&table[52] = 16777472;
  *(_DWORD *)&table[56] = 0;
  *(_DWORD *)&table[60] = 0;
  *(_DWORD *)&table[64] = 256;
  *(_DWORD *)&table[68] = 65537;
  *(_DWORD *)&table[72] = 0;
  *(_DWORD *)&table[76] = 0;
  *(_DWORD *)&table[80] = 16842752;
  *(_DWORD *)&table[84] = 0;
  *(_DWORD *)&table[88] = 1;
  *(_DWORD *)&table[92] = 0;
  *(_DWORD *)&table[96] = 0x10000;
  *(_DWORD *)&table[100] = 1;
  *(_DWORD *)&table[104] = 256;
  *(_DWORD *)&table[108] = 0;
  *(_DWORD *)&table[112] = 0x1000000;
  *(_DWORD *)&table[116] = 0x1000000;
  *(_DWORD *)&table[120] = 0x10000;
  *(_DWORD *)&table[124] = 0;
  *(_DWORD *)&table[128] = 0;
  *(_DWORD *)&table[132] = 256;
  *(_DWORD *)&table[136] = 1;
  *(_DWORD *)&table[140] = 1;
  *(_DWORD *)&table[144] = 0;
  *(_DWORD *)&table[148] = 0x10000;
  *(_DWORD *)&table[152] = 0x1000000;
  *(_DWORD *)&table[156] = 256;
  *(_DWORD *)&table[160] = 0;
  *(_DWORD *)&table[164] = 0x1000000;
  *(_DWORD *)&table[168] = 0;
  *(_DWORD *)&table[172] = 257;
  *(_DWORD *)&table[176] = 0;
  *(_DWORD *)&table[180] = 0;
  *(_DWORD *)&table[184] = 16777472;
  *(_DWORD *)&table[188] = 0x10000;
  *(_DWORD *)&table[192] = 0;
  *(_DWORD *)&table[196] = 0;
  *(_DWORD *)&table[200] = 65537;
  *(_DWORD *)&table[204] = 0x10000;
  *(_DWORD *)&table[208] = 0;
  *(_DWORD *)&table[212] = 0;
  *(_DWORD *)&table[216] = 65792;
  *(_DWORD *)&table[220] = 0x1000000;
  *(_DWORD *)&table[224] = 0;
  *(_DWORD *)&table[228] = 0;
  *(_DWORD *)&table[232] = 0x1000000;
  *(_DWORD *)&table[236] = 16777217;
  *(_DWORD *)&table[240] = 0;
  *(_DWORD *)&table[244] = 0;
  *(_DWORD *)&table[248] = 0;
  *(_DWORD *)&table[252] = 16843008;
  index = 0;
  do
  {
    for ( i = 0; ; ++i )
    {
      if ( i >= 64 )
      {
        printf("input error\n");
        system("PAUSE");
        exit(-1);
      }
      if ( byte_40DA68[i] == (unsigned __int8)g_inputKey[index] )
        break;
    }
    inputIndexKey[0][index++] = i;
  }
  while ( index < 16 );
  printf("\n");
  v3 = 0x10;
  v17 = 0x10;
  v15 = 2 - (_DWORD)inputIndexKey[1];
  do
  {
    v4 = (char *)inputIndexKey + v3;
    v13 = (char *)inputIndexKey + v3;
    v5 = 0;
    do
    {
      pkey3CharBuf = key3CharBuf;
      v7 = (int)&v4[v15];
      cnt = 4;
      do
      {
        v8 = (v7 - 2) % 16;
        if ( table[v5 + v8] )
          *pkey3CharBuf++ = *((_BYTE *)&cnt + v8 + v17);
        v9 = (v7 - 1) % 16;
        if ( table[v5 + v9] )
          *pkey3CharBuf++ = *((_BYTE *)&cnt + v9 + v17);
        if ( table[v5 + v7 % 16] )
          *pkey3CharBuf++ = *((_BYTE *)&cnt + v7 % 16 + v17);
        v10 = (v7 + 1) % 16;
        if ( table[v5 + v10] )
          *pkey3CharBuf++ = *((_BYTE *)&cnt + v10 + v17);
        v7 += 4;
        --cnt;
      }
      while ( cnt );
      *v13 = byte_40FEF0[64 * ((unsigned __int8)key3CharBuf[1] + ((unsigned __int8)key3CharBuf[0] << 6))
                       + (unsigned __int8)key3CharBuf[2]];
      v5 += 16;
      v4 = v13++ + 1;
    }
    while ( v5 < 0x100 );
    v15 -= 16;
    v3 = v17 + 16;
    v17 = v3;
  }
  while ( v3 < 320 );
  v11 = 0;
  do
  {
    if ( (unsigned __int8)inputIndexKey[0x13][v11] != byte_40FEE0[v11] )
      return printf("serial error\n");
    ++v11;
  }
  while ( v11 < 16 );
  do
    printf("%c", (unsigned __int8)byte_40DA68[(unsigned int)(unsigned __int8)inputIndexKey[9][v0++] >> 1]);
  while ( v0 < 16 );
  return printf("\n");
}
       
1、初始化了一个16*16的数组 table:
	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,
	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,
          2、从"abcdefghijklmnopqrstuvwxyz+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"查找输入kjey,并替换成对应字符所在的位置索引。
          2、从"abcdefghijklmnopqrstuvwxyz+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"查找输入kjey,并替换成对应字符所在的位置索引。
        可以把输入16个字符变换后的数据比作16把钥匙,并将其存储在第0层房间inputIndexKey[0]中。而最内层循环的作用是根据变量索引index,获取与下层index相关的本层的三把钥匙,而本层具体三把钥匙与下层相关是由前面定义的talbe(16*16)来决定的。观察talbe,可以看到当前层的16把钥匙中的有且仅有3把钥匙与下层的某个钥匙相关。通过最内层循环索引 talbe后得到3把钥匙,放到key3CharBuf[中],而下层的钥匙数值value为:
 value = key3CharBuf[0]*64*64 + key3CharBuf [1]*64 + key3CharBuf[0]。然后索引g_constKey[64][64][64]常量表, 因此取索引对应的数值作为下层相应的钥匙。 g_constKey存储的数据范围为:(0~63)。
 6、中间层循环
        使index数值从0 开始依次循环16次,从而获得下层的所有16把钥匙,才可以到最外层循环,进入到下一层。需要注意的是:
        当进行索引第i把钥匙,首先要确定索引 table的位置,即为table[i][i]开始,比如:
 value = key3CharBuf[0]*64*64 + key3CharBuf [1]*64 + key3CharBuf[0]。然后索引g_constKey[64][64][64]常量表, 因此取索引对应的数值作为下层相应的钥匙。 g_constKey存储的数据范围为:(0~63)。
 value = key3CharBuf[0]*64*64 + key3CharBuf [1]*64 + key3CharBuf[0]。然后索引g_constKey[64][64][64]常量表, 因此取索引对应的数值作为下层相应的钥匙。 g_constKey存储的数据范围为:(0~63)。
 6、中间层循环
        使index数值从0 开始依次循环16次,从而获得下层的所有16把钥匙,才可以到最外层循环,进入到下一层。需要注意的是:
        当进行索引第i把钥匙,首先要确定索引 table的位置,即为table[i][i]开始,比如:
        索引第0把钥匙,则取 table[0][0] ~ table[0][15]
        索引第1把钥匙,则取 table[1][1] ~table[1][15]、 table[1][0]
        索引第0把钥匙,则取 table[0][0] ~ table[0][15]
        索引第1把钥匙,则取 table[1][1] ~table[1][15]、 table[1][0]
       通过分析中间层循环不难得出下一层钥匙与本次钥匙的关系,假如当前层是a,其16把钥匙为 a0-a15, 下一层为b,其16把钥匙为b0-b15:    
b0        =      g_constKey[ a0*64*64               +             a1*64               +                a2]
b1        =      g_constKey[ a3*64*64               +             a4*64               +                a0] 
b2        =      g_constKey[ a5*64*64               +             a6*64               +                a0]  
b3        =      g_constKey[ a5*64*64               +             a7*64               +                a1]
b4        =      g_constKey[ a4*64*64               +             a6*64               +                a1] 
b5        =      g_constKey[ a8*64*64               +             a2*64               +                a3]       
b6        =      g_constKey[ a9*64*64               +             a8*64               +                a4] 
b7        =      g_constKey[ a7*64*64               +             a10*64              +                a3] 
b8        =      g_constKey[ a8*64*64               +             a12*64              +                a5] 
b9        =      g_constKey[ a11*64*64              +             a13*64              +                a6]
b10       =      g_constKey[ a12*64*64              +             a13*64              +                a7]
b11       =      g_constKey[ a11*64*64              +             a14*64              +                a9]
b12       =      g_constKey[ a14*64*64              +             a8*64               +                a10]
b13       =      g_constKey[ a15*64*64              +             a9*64               +                a10]
b14       =      g_constKey[ a15*64*64              +             a11*64              +                a12]
b15       =      g_constKey[ a15*64*64              +             a13*64              +                a14]  
7、最外层循环
         获得下层所有钥匙后,就可以开启下层的门锁,从而进入下一层,依次循环一共循环20次。
8、第20次循环的钥匙即: inputIndexKey [19]与全局变量byte_40DA68[16]必须相等,如果不同则返回失败,如果相同,则输入第9层相关信息,成功。
二、算法分析
        现在我们需要做的是,根据最后一层的钥匙,来逆推前一层的钥匙,一直到第0层,从而拿到key。可以利用本层与下层的钥匙关系,进行暴力穷举,是可以获得最原始的初始钥匙,获得key大概需要4个小时。下面是个优化的算法,大概需要3-5分钟获得原始钥匙。
         已知本层所有钥匙,来获得上一层的所有钥匙:
         存在16把钥匙,就是存在16个方程,通过遍历 g_constKey 表,可知每个方程共有4096个解。假定本层第0把钥匙对应的上层3把钥匙a0, a1,a2确定,则可知本层第1、2、3、4、5、6把钥匙都分别有64个解。然后再以第1把钥匙为基础,遍历其64中可能,通过各钥匙之间的关系,可知其中每一种可能都可以锁定剩余11把钥匙的可能性。以次为基础,开始依次遍历校验,先获取16把钥匙每把的可能4096个解,然后循环4096*64次即可碰撞出上一层所有钥匙。

#include "stdafx.h"
#include <windows.h>     
extern char g_constKey[0x40000];
extern unsigned char g_indexKey[0x100];
typedef struct {
	unsigned char x;
	unsigned char y;
	unsigned char z;
}result;
typedef struct nextRest{
	unsigned char m;
	unsigned char n;
}nextRest;
typedef struct nextRestInfo{
	int count;
	nextRest result[640];
}nextRestInfo;
typedef struct {
	//0--a0,a1,a2
	//1--a3,a4,a0
	result r[16][40960];
}allResult;
unsigned char arm[16] = { 0x14, 0x22, 0x1E, 0x10, 0x38, 0x30, 0x18, 0x10, 0x04, 0x1A, 0x24, 0x08, 0x02, 0x26, 0x38, 0x2A };
char srt[] = "abcdefghijklmnopqrstuvwxyz+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
unsigned char newArm[16];
nextRestInfo nr56;
nextRestInfo nr34;
nextRestInfo nr57;
nextRestInfo nr46;
nextRestInfo nr83;
nextRestInfo nr94;
allResult allr;
bool getmnResult(nextRestInfo* nr, unsigned char a, int index, int xyz)
{
	int count = 0;
	for (int i = 0; i < 4096; i++)
	{
		if (1 == xyz)
		{
			if (allr.r[index][i].x == a)
			{
				nr->result[count].m = allr.r[index][i].y;
				nr->result[count].n = allr.r[index][i].z;
				if (count < 64)
					count++;
				else
				{
					printf("ERROR:   count > 64");
					return false;
				}
			}
		}
		if (2 == xyz)
		{
			if (allr.r[index][i].y == a)
			{
				nr->result[count].m = allr.r[index][i].x;
				nr->result[count].n = allr.r[index][i].z;
				if (count < 64)
					count++;
				else
				{
					printf("ERROR:   count > 64");
					return false;
				}
			}
		}
		if (3 == xyz)
		{
			if (allr.r[index][i].z == a)
			{
				nr->result[count].m = allr.r[index][i].x;
				nr->result[count].n = allr.r[index][i].y;
				if (count < 64)
				{
					count++;
				}
				else
				{
					printf("ERROR:   count > 64");
					return false;
				}
			}	
		}
	}
	return true;
}

unsigned char geta7Bya5(unsigned char a5)
{
	for (int i = 0; i < 64; i++)
	{
		if (nr57.result[i].m == a5)
			return nr57.result[i].n;
	}
	return 0xff;
}
unsigned char geta4Bya6(unsigned char a6)
{
	for (int i = 0; i < 64; i++)
	{
		if (nr46.result[i].n == a6)
			return nr46.result[i].m;
	}
	return 0xff;
}
unsigned char geta3Bya4(unsigned char a4)
{
	for (int i = 0; i < 64; i++)
	{
		if (nr34.result[i].n== a4)
			return nr34.result[i].m;
	}
	return 0xff;
}
unsigned char geta8Bya3(unsigned char a3)
{
	for (int i = 0; i < 64; i++)
	{
		if (nr83.result[i].n == a3)
			return nr34.result[i].m;
	}
	return 0xff;
}
unsigned char geta9Bya4(unsigned char a4)
{
	for (int i = 0; i < 64; i++)
	{
		if (nr94.result[i].n == a4)
			return nr94.result[i].m;
	}
	return 0xff;
}
unsigned char geta10Bya7a3()
{
	for (int i = 0; i < 4096; i++)
	{
		if (allr.r[7][i].x == newArm[7] && allr.r[7][i].z == newArm[3])
			return allr.r[7][i].y;
	}
	return 0xff;
}
unsigned char geta12Bya8a5()
{
	for (int i = 0; i < 4096; i++)
	{
		if (allr.r[8][i].x == newArm[8] && allr.r[8][i].z == newArm[5])
			return allr.r[8][i].y;
	}
	return 0xff;
}
unsigned char geta13Bya11a6()
{
	for (int i = 0; i < 4096; i++)
	{
		if (allr.r[9][i].x == newArm[11] && allr.r[9][i].z == newArm[6])
			return allr.r[9][i].y;
	}
	return 0xff;
}
unsigned char geta14Bya8a10()
{
	for (int i = 0; i < 4096; i++)
	{
		if (allr.r[12][i].y == newArm[8] && allr.r[12][i].z == newArm[10])
			return allr.r[12][i].x;
	}
	return 0xff;
}
unsigned char geta11Bya14a9()
{
	for (int i = 0; i < 4096; i++)
	{
		if (allr.r[11][i].y == newArm[14] && allr.r[11][i].z == newArm[9])
			return allr.r[11][i].x;
	}
	return 0xff;
}
unsigned char geta15Bya9a10()
{
	for (int i = 0; i < 4096; i++)
	{
		if (allr.r[13][i].y == newArm[9] && allr.r[13][i].z == newArm[10])
			return allr.r[13][i].x;
	}
	return 0xff;
}
int _tmain(int argc, _TCHAR* argv[])
{
	int count = 0;
	unsigned char block = 0;
	unsigned char  hh = 0;
	unsigned char ll = 0;
	int binggo = 0;
	
	printf("开始遍历: \r\n");
	for (int loop = 0; loop < 19; loop++)
	{
		//获取16组解
		for (int k = 0; k <16 ; k++)
		{
			int count = 0;
			for (int i = 0; i < 0x40000; i++)
			{
				if (g_constKey[i] == arm[k])
				{
					block = i / (64 * 64);
					hh = (i % (64 * 64)) / 64;
					ll = i - block*(4 * 16 * 64) - 64 * hh;
					allr.r[k][count].x = block;
					allr.r[k][count].y = hh;
					allr.r[k][count].z = ll;
					count++;
				}
			}
		}
		for (int indexa1a2a3 = 0; indexa1a2a3 < 4096; indexa1a2a3++)
		{
			newArm[0] = allr.r[0][indexa1a2a3].x;
			newArm[1] = allr.r[0][indexa1a2a3].y;
			newArm[2] = allr.r[0][indexa1a2a3].z;
			//根据a0获得a3,a4可能解集合
			//m=x,n=y
			getmnResult(&nr34, newArm[0],1,3);
			getmnResult(&nr56, newArm[0],2,3);
			getmnResult(&nr57, newArm[1],3,3);
			getmnResult(&nr46, newArm[1],4,3);
			getmnResult(&nr83, newArm[2],5,2);
			getmnResult(&nr94, newArm[2],6,2);
			for (int mnIndex = 0; mnIndex < 64; mnIndex++)
			{
				newArm[5] = nr56.result[mnIndex].m;
				newArm[6] = nr56.result[mnIndex].n;
				newArm[7] = geta7Bya5(newArm[5]);
				newArm[4] = geta4Bya6(newArm[6]);
				newArm[3] = geta3Bya4(newArm[4]);
				newArm[8] = geta8Bya3(newArm[3]);
				newArm[9] = geta9Bya4(newArm[4]);
				newArm[10] = geta10Bya7a3();
				newArm[12] = geta12Bya8a5();
				newArm[14] = geta14Bya8a10();
				newArm[11] = geta11Bya14a9();
				newArm[13] = geta13Bya11a6();
				newArm[15] = geta15Bya9a10();			
				if (g_constKey[64 * 64 * newArm[0] + 64 * newArm[1] + newArm[2]] != arm[0])continue;
				if (g_constKey[64 * 64 * newArm[3] + 64 * newArm[4] + newArm[0]] != arm[1])continue;
				if (g_constKey[64 * 64 * newArm[5] + 64 * newArm[6] + newArm[0]] != arm[2])continue;
				if (g_constKey[64 * 64 * newArm[5] + 64 * newArm[7] + newArm[1]] != arm[3])continue;
				if (g_constKey[64 * 64 * newArm[4] + 64 * newArm[6] + newArm[1]] != arm[4])continue;
				if (g_constKey[64 * 64 * newArm[8] + 64 * newArm[2] + newArm[3]] != arm[5])continue;
				if (g_constKey[64 * 64 * newArm[9] + 64 * newArm[2] + newArm[4]] != arm[6])continue;
				if (g_constKey[64 * 64 * newArm[7] + 64 * newArm[10] + newArm[3]] != arm[7])continue;
				if (g_constKey[64 * 64 * newArm[8] + 64 * newArm[12] + newArm[5]] != arm[8])continue;
				if (g_constKey[64 * 64 * newArm[11] + 64 * newArm[13] + newArm[6]] != arm[9])continue;
				if (g_constKey[64 * 64 * newArm[12] + 64 * newArm[13] + newArm[7]] != arm[10])continue;
				if (g_constKey[64 * 64 * newArm[11] + 64 * newArm[14] + newArm[9]] != arm[11])continue;
				if (g_constKey[64 * 64 * newArm[14] + 64 * newArm[8] + newArm[10]] != arm[12])continue;
				if (g_constKey[64 * 64 * newArm[15] + 64 * newArm[9] + newArm[10]] != arm[13]) continue;
				if (g_constKey[64 * 64 * newArm[15] + 64 * newArm[11] + newArm[12]] != arm[14]) continue;
				if (g_constKey[64 * 64 * newArm[15] + 64 * newArm[13] + newArm[14]] != arm[15]) continue;

				//获得结果
				binggo++;
				printf("倒数第%2d轮: ", 19-loop);
				for (int c = 0; c < 16; c++)
					printf("0x%02x ", newArm[c]);
				printf("\r\n");
				memcpy(arm, newArm, 16);
				break;
			}
		}
	}
	printf("\n遍历完成:sn = ");
	for (int i = 0; i < 16; i++)
	{
		arm[i] = srt[arm[i]];
		printf("%c", arm[i]);
	}
	return 0;
}
 运行结果如下:
开始遍历:
倒数第19轮: 0x0f 0x0b 0x07 0x0b 0x35 0x03 0x19 0x1f 0x0b 0x31 0x3b 0x33 0x03 0x07 0x15 0x37
倒数第18轮: 0x3a 0x26 0x00 0x3a 0x34 0x06 0x2c 0x3c 0x0e 0x1e 0x0a 0x26 0x24 0x18 0x3c 0x18
倒数第17轮: 0x0f 0x07 0x0d 0x15 0x23 0x3f 0x3f 0x19 0x11 0x0d 0x03 0x25 0x37 0x3b 0x19 0x31
倒数第16轮: 0x0c 0x36 0x16 0x06 0x06 0x26 0x04 0x2e 0x0c 0x0c 0x3a 0x10 0x10 0x16 0x36 0x22
倒数第15轮: 0x0f 0x1f 0x33 0x0d 0x2b 0x2b 0x19 0x19 0x3f 0x33 0x35 0x2d 0x27 0x1b 0x11 0x07
倒数第14轮: 0x3a 0x12 0x3c 0x0e 0x2c 0x3c 0x2e 0x08 0x1e 0x22 0x3c 0x12 0x26 0x18 0x0e 0x0e
倒数第13轮: 0x19 0x2f 0x03 0x29 0x15 0x03 0x11 0x29 0x15 0x3f 0x33 0x09 0x1f 0x1d 0x23 0x33
倒数第12轮: 0x38 0x1e 0x38 0x2a 0x0e 0x16 0x1e 0x2a 0x16 0x2c 0x1a 0x1e 0x3e 0x10 0x08 0x28
倒数第11轮: 0x27 0x3d 0x25 0x3f 0x2d 0x29 0x19 0x21 0x27 0x39 0x33 0x05 0x17 0x13 0x0d 0x15
倒数第10轮: 0x30 0x1c 0x28 0x22 0x24 0x08 0x22 0x10 0x00 0x16 0x10 0x24 0x0c 0x1c 0x1c 0x06
倒数第 9轮: 0x25 0x05 0x1f 0x2d 0x27 0x33 0x19 0x0b 0x01 0x0d 0x21 0x31 0x15 0x31 0x3b 0x17
倒数第 8轮: 0x16 0x2e 0x36 0x10 0x08 0x28 0x02 0x20 0x06 0x00 0x28 0x0e 0x14 0x0a 0x04 0x22
倒数第 7轮: 0x35 0x2d 0x31 0x17 0x3b 0x1d 0x29 0x03 0x21 0x0b 0x0b 0x3f 0x05 0x31 0x11 0x1d
倒数第 6轮: 0x3e 0x0a 0x2a 0x02 0x2a 0x08 0x24 0x1e 0x1e 0x3a 0x38 0x1e 0x2c 0x2a 0x1c 0x3c
倒数第 5轮: 0x13 0x01 0x27 0x39 0x2f 0x25 0x1b 0x09 0x2d 0x13 0x11 0x1d 0x31 0x0b 0x37 0x17
倒数第 4轮: 0x2e 0x22 0x24 0x0e 0x2a 0x36 0x00 0x0e 0x34 0x2a 0x32 0x00 0x14 0x20 0x14 0x08
倒数第 3轮: 0x21 0x1f 0x17 0x03 0x27 0x2b 0x29 0x01 0x15 0x1f 0x1b 0x05 0x25 0x39 0x35 0x23
倒数第 2轮: 0x20 0x30 0x32 0x16 0x32 0x12 0x06 0x32 0x3c 0x1a 0x16 0x18 0x30 0x22 0x24 0x1e
倒数第 1轮: 0x11 0x2b 0x21 0x05 0x3f 0x01 0x25 0x0b 0x39 0x13 0x33 0x09 0x3f 0x39 0x35 0x25

遍历完成:sn = rPFf9bJl3tXj93ZJ
sn 为 “rPFf9bJl3tXj93ZJ”
      
       通过分析中间层循环不难得出下一层钥匙与本次钥匙的关系,假如当前层是a,其16把钥匙为 a0-a15, 下一层为b,其16把钥匙为b0-b15:    
b0        =      g_constKey[ a0*64*64               +             a1*64               +                a2]
b1        =      g_constKey[ a3*64*64               +             a4*64               +                a0] 
b2        =      g_constKey[ a5*64*64               +             a6*64               +                a0]  
b3        =      g_constKey[ a5*64*64               +             a7*64               +                a1]
b4        =      g_constKey[ a4*64*64               +             a6*64               +                a1] 
b5        =      g_constKey[ a8*64*64               +             a2*64               +                a3]       
b6        =      g_constKey[ a9*64*64               +             a8*64               +                a4] 
b7        =      g_constKey[ a7*64*64               +             a10*64              +                a3] 
b8        =      g_constKey[ a8*64*64               +             a12*64              +                a5] 
b9        =      g_constKey[ a11*64*64              +             a13*64              +                a6]
b10       =      g_constKey[ a12*64*64              +             a13*64              +                a7]
b11       =      g_constKey[ a11*64*64              +             a14*64              +                a9]
b12       =      g_constKey[ a14*64*64              +             a8*64               +                a10]
b13       =      g_constKey[ a15*64*64              +             a9*64               +                a10]
b14       =      g_constKey[ a15*64*64              +             a11*64              +                a12]
b15       =      g_constKey[ a15*64*64              +             a13*64              +                a14]  
7、最外层循环
         获得下层所有钥匙后,就可以开启下层的门锁,从而进入下一层,依次循环一共循环20次。
8、第20次循环的钥匙即: inputIndexKey [19]与全局变量byte_40DA68[16]必须相等,如果不同则返回失败,如果相同,则输入第9层相关信息,成功。
二、算法分析
        现在我们需要做的是,根据最后一层的钥匙,来逆推前一层的钥匙,一直到第0层,从而拿到key。可以利用本层与下层的钥匙关系,进行暴力穷举,是可以获得最原始的初始钥匙,获得key大概需要4个小时。下面是个优化的算法,大概需要3-5分钟获得原始钥匙。
         已知本层所有钥匙,来获得上一层的所有钥匙:
         存在16把钥匙,就是存在16个方程,通过遍历 g_constKey 表,可知每个方程共有4096个解。假定本层第0把钥匙对应的上层3把钥匙a0, a1,a2确定,则可知本层第1、2、3、4、5、6把钥匙都分别有64个解。然后再以第1把钥匙为基础,遍历其64中可能,通过各钥匙之间的关系,可知其中每一种可能都可以锁定剩余11把钥匙的可能性。以次为基础,开始依次遍历校验,先获取16把钥匙每把的可能4096个解,然后循环4096*64次即可碰撞出上一层所有钥匙。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2018-6-30 14:04 被oooAooo编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//