首页
社区
课程
招聘
[原创]2019看雪CTF 晋级赛Q2 第4题-达芬奇密码
2019-6-24 14:30 4061

[原创]2019看雪CTF 晋级赛Q2 第4题-达芬奇密码

2019-6-24 14:30
4061

初步分析

程序主逻辑在sub_1201EA0函数中,有如下条件:
     输入字符串长度为》=16。
     checkFun()函数返回ture为正确结果,而 checkFun()为加密函数,需要解密还原。
int __thiscall sub_1201EA0(CWnd *this)
{
  CWnd *v1; // esi
  int v2; // eax
  WCHAR String; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char key; // [esp+20Ch] [ebp-110h]
  char v7; // [esp+20Dh] [ebp-10Fh]
  DWORD v8; // [esp+30Ch] [ebp-10h]
  CWnd *v9; // [esp+310h] [ebp-Ch]
  int v10; // [esp+314h] [ebp-8h]
  DWORD flOldProtect; // [esp+318h] [ebp-4h]

  v1 = this;
  v9 = this;
  String = 0;
  memset(&v5, 0, 0x1FEu);
  key = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 1000, &String, 20);
  if ( wcslen(&String) == 16 )
  {
    v2 = 0;
    while ( !(*(&String + v2) & 0xFF00) )
    {
      *(&key + v2) = *((_BYTE *)&String + 2 * v2);
      if ( ++v2 >= 16 )
      {
        v8 = 64;
        flOldProtect = 0;
        VirtualProtect(checkFun, 0xD17u, 0x40u, &flOldProtect);
        if ( GetLastError() )
          return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
        qmemcpy(checkFun, byte_13647B8, 0x330u);
        VirtualProtect(checkFun, 0xD17u, flOldProtect, &v8);
        if ( !GetLastError() )
        {
          v10 = 0;
          v10 = checkFun(&key);
          if ( v10 == 1 )
            return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
        }
        v1 = v9;
        return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
      }
    }
  }

还原checkFun函数

qmemcpy(checkFun, byte_13647B8, 0x330u);可以看到从全局变量地址 byte_13647B8 还原了0x330bytes数据。查看 byte_13647B8引用。
 do
  {
    byte_13647B8[v2] ^= 0xABu;
    ++v2;
  }
  while ( v2 < 0x330 );
初始化时有个以或0xAB操作。我们可以将原始的exe文件解密还原另存为新的exe文件继续分析。

还原后的checkFun函数

signed int __cdecl checkFun(char *key)
{
  signed int index; // eax
  char v2; // cl
  signed int v3; // ecx
  signed int v4; // eax
  signed int v5; // eax
  signed int i; // esi
  signed int v7; // ecx
  __int16 curKey_low; // dx
  _BYTE *v9; // edi
  __int16 v10; // ax
  signed int v11; // eax
  signed int v12; // ecx
  unsigned __int16 v13; // bx
  signed int v14; // esi
  signed int v15; // ecx
  __int16 v16; // dx
  _BYTE *v17; // edi
  __int16 v18; // ax
  signed int v19; // eax
  signed int v20; // ecx
  unsigned __int16 v21; // bx
  unsigned int v22; // eax
  signed int v23; // ecx
  unsigned __int16 v24; // dx
  char v25; // dl
  signed int v26; // eax
  __int16 v27; // si
  int v28; // eax
  _BYTE v30[8]; // [esp+8h] [ebp-90h]
  _BYTE v31[8]; // [esp+10h] [ebp-88h]
  int v32; // [esp+18h] [ebp-80h]
  int v33; // [esp+1Ch] [ebp-7Ch]
  int v34; // [esp+20h] [ebp-78h]
  int v35; // [esp+24h] [ebp-74h]
  _BYTE key_low[8]; // [esp+28h] [ebp-70h]
  _BYTE v37[8]; // [esp+30h] [ebp-68h]
  _BYTE v38[8]; // [esp+38h] [ebp-60h]
  _BYTE key_high[8]; // [esp+40h] [ebp-58h]
  _BYTE v40[40]; // [esp+48h] [ebp-50h]
  _BYTE v41[40]; // [esp+70h] [ebp-28h]

  v30[4] = 0x81u;
  v31[3] = 0x81u;
  index = 0;
  v30[0] = 0x16;
  v30[1] = 0x96u;
  v30[2] = 0x8Cu;
  v30[3] = 0xE3u;
  v30[5] = 0x98u;
  v30[6] = 0x6E;
  v30[7] = 0x64;
  v31[0] = 0x84u;
  v31[1] = 8;
  v31[2] = 0xDCu;
  v31[4] = 0xBEu;
  v31[5] = 0x4D;
  v31[6] = 0x48;
  v31[7] = 0x4F;
  v32 = 0;
  v33 = 0;
  v34 = 0;
  v35 = 0;
  *(_DWORD *)key_low = 0;
  *(_DWORD *)&key_low[4] = 0;
  *(_DWORD *)key_high = 0;
  *(_DWORD *)&key_high[4] = 0;
  do
  {
    v2 = v31[index] ^ key[index + 8];
    key_low[index] = v30[index] ^ v30[index + key - v30];
    key_high[index++] = v2;
  }
  while ( index < 8 );
  *(_DWORD *)v30 = 0;
  *(_DWORD *)v41 = 0;
  *(_DWORD *)&v41[4] = 0;
  *(_DWORD *)&v41[8] = 0;
  *(_DWORD *)&v41[12] = 0;
  v41[16] = 0;
  *(_DWORD *)&v41[20] = 0;
  *(_DWORD *)&v41[24] = 0;
  *(_DWORD *)&v41[28] = 0;
  *(_DWORD *)&v41[32] = 0;
  v41[36] = 0;
  *(_DWORD *)v40 = 0;
  *(_DWORD *)&v40[4] = 0;
  *(_DWORD *)&v40[8] = 0;
  *(_DWORD *)&v40[12] = 0;
  v40[16] = 0;
  *(_DWORD *)&v40[20] = 0;
  *(_DWORD *)&v40[24] = 0;
  *(_DWORD *)&v40[28] = 0;
  *(_DWORD *)&v40[32] = 0;
  v40[36] = 0;
  *(_DWORD *)&v30[4] = 0;
  *(_DWORD *)v31 = 0;
  *(_DWORD *)&v31[4] = 0;
  LOBYTE(v32) = 0;
  v3 = 8;
  v30[0] = 8;
  v4 = 7;
  do
  {
    if ( key_low[v4] )
      break;
    --v3;
    --v4;
  }
  while ( v4 >= 0 );
  if ( v3 == 8 )
  {
    v5 = 7;
    do
    {
      if ( key_high[v5] )
        break;
      --v3;
      --v5;
    }
    while ( v5 >= 0 );
    if ( v3 == 8 && !(key_low[7] & 0xF0) )      // 高四位为0
    {
      i = 0;
      do
      {
        *(_DWORD *)v37 = 0;
        *(_DWORD *)&v37[4] = 0;
        *(_DWORD *)v38 = 0;
        *(_DWORD *)&v38[4] = 0;
        v7 = 0;
        curKey_low = (unsigned __int8)key_low[i];
        v9 = &v37[i];
        do
        {
          v10 = (unsigned __int8)v38[i] + curKey_low * (unsigned __int8)key_low[v7];
          v9[v7] = v38[i] + curKey_low * key_low[v7];
          ++v7;
          v38[i] = HIBYTE(v10);
        }
        while ( v7 < 8 );
        LOBYTE(v11) = 0;
        v12 = 0;
        do
        {
          v13 = (char)v11 + (unsigned __int8)v41[v12 + i] + (unsigned __int8)v9[v12];
          v41[v12++ + i] = v13;
          v11 = (signed int)v13 >> 8;
        }
        while ( v12 < 9 );
        ++i;
      }
      while ( i < 8 );
      v14 = 0;
      do
      {
        *(_DWORD *)v37 = 0;
        *(_DWORD *)&v37[4] = 0;
        *(_DWORD *)v38 = 0;
        *(_DWORD *)&v38[4] = 0;
        v15 = 0;
        v16 = (unsigned __int8)key_high[v14];
        v17 = &v37[v14];
        do
        {
          v18 = (unsigned __int8)v38[v14] + v16 * (unsigned __int8)key_high[v15];
          v17[v15] = v38[v14] + v16 * key_high[v15];
          ++v15;
          v38[v14] = HIBYTE(v18);
        }
        while ( v15 < 8 );
        LOBYTE(v19) = 0;
        v20 = 0;
        do
        {
          v21 = (char)v19 + (unsigned __int8)v41[v20 + 0x14 + v14] + (unsigned __int8)v17[v20];
          v41[v20++ + 20 + v14] = v21;
          v19 = (signed int)v21 >> 8;
        }
        while ( v20 < 9 );
        ++v14;
      }
      while ( v14 < 8 );
      LOBYTE(v22) = v40[0x10];
      v23 = 0;
      do
      {
        v24 = (unsigned __int8)v22 + 7 * (unsigned __int8)v41[v23 + 0x14];
        v40[v23++] = v24;
        v22 = (unsigned int)v24 >> 8;
      }
      while ( v23 < 17 );
      v40[16] = HIBYTE(v24);
      v25 = 0;
      v26 = 0;
      do
      {
        v27 = (unsigned __int8)v41[v26] - (unsigned __int8)v40[v26] - v25;
        v40[v26 + 0x14] = v27;
        if ( v27 < 0 )
          v25 = 1;
        ++v26;
      }
      while ( v26 < 17 );
      if ( !v25 )
      {
        v28 = 0;
        while ( v40[v28 + 0x14] == v30[v28] )
        {
          if ( ++v28 >= 17 )
            return 1;
        }
      }
    }
  }
  return 0;
}
该函数完成了一个算式检查。x^2-7y^2=8。其中有个限制条件X的高四位为0,x+y长度》=16
这是一个非标的佩尔方程,通解原理网上比较多,不说了。

// CTF4new.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<string>
using namespace std;
typedef  long long ll;
//const int mod = 8191;
const ll mod = 0x1fffffffffffffff;
struct matrix{ ll a[2][2]; matrix(){ memset(a, 0, sizeof(a)); } };
matrix ans;
ll xp = 0;
ll yp = 0;
ll x = 0;
ll y = 0;
matrix multi(matrix a, matrix b)
{
	matrix ans;
	for (int i = 0; i<2; i++)
	for (int j = 0; j<2; j++)
	for (int k = 0; k<2; k++)
		ans.a[i][j] = (ans.a[i][j] + a.a[i][k] * b.a[k][j] % mod) % mod;
	return ans;
}
matrix qpow(matrix res, ll k)
{
	while (k)
	{
		if (k & 1)
			res = multi(res, ans);
		k /= 2;
		ans = multi(ans, ans);
	}
	return res;
}
int main()
{
	ll n, k;
	n = 7;
	k = 1;
	
	while (k<=0x1000)
	{
		ll nn = sqrt(n), keepx, keepy;
		if (nn*nn == n){ printf("No answers can meet such conditions\n"); continue; }
		for (int i = 1;; i++)
		{ 
			ll y = i*i*n + 1; 
			ll yy = sqrt(y); 
			if (yy*yy == i*i*n + 1)
			{ 
				keepy = i;
				keepx = yy; 
				//printf("x=%llx--y=%llx\n",keepx,keepy);
				break; 
			}
		}
		ans.a[0][0] = keepx%mod;
		ans.a[0][1] = n*keepy%mod;
		ans.a[1][0] = keepy%mod;
		ans.a[1][1] = keepx%mod;
		matrix res;
		res.a[0][0] = 1, res.a[1][1] = 1;
		matrix ans = qpow(res, k - 1);
		xp = (ans.a[0][0] * keepx%mod + ans.a[0][1] * keepy%mod + mod) % mod;
		yp = (ans.a[1][0] * keepx%mod + ans.a[1][1] * keepy%mod + mod) % mod;
		x = 6 * xp + 7 * 2 * yp;
		y = 6 * yp + xp * 2;
		//printf("%llx--%llx\n", x, y);
		k++;
		//05xxxxxxxxxxxxxx
		//(0x100000000000000<x<0x1000000000000000)
		if (x<0x100000000000000)
		{
			continue;
		}
		if (x>0x1000000000000000)
		{
			break;
		}
		printf("%llx--%llx\n", x, y);




	}
	return 0;
}

根据限制条件,找到已给特解: 557f3b3b9e1a55a--2050988b2bd38de
constLow = {0x16,0x96,0x8C,0xE3,0x81,0x98,0x6E,0x64};
constHigh = {0x84,8, 0xDC,0x81,0xBE,0x4D,0x48,0x4F};
异或常量后得到flag:L3mZ2k9aZ0a36DMM





[培训]《安卓高级研修班(网课)》月薪三万计划

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