首页
社区
课程
招聘
[原创] 第十三题 NeuralCrackme WriteUp
2018-7-10 16:09 2128

[原创] 第十三题 NeuralCrackme WriteUp

2018-7-10 16:09
2128

Pediy CTF 2018 - NeuralCrackme Writeup

这道题看题目名似乎是一道和神经网络有关的题目,实际上……确实有关系,不过关系似乎不是很大= =

程序分析

程序中所有的字符串常量都是动态解密的,调一下就能知道。

 

程序首先读入Flag,然后检验Flag长度是否为10,并且是否为0-9 A-F之间的字符。然后,程序将Flag转为对应的bytes(5个字节),拆成两段,第一段2字节,第二段3字节。然后将这些字节之后补0补齐8个字节,转成IEEE754 double浮点数。

 

接下来是一个看上去有点懵的函数,传入了这两个浮点数,进行了一堆奇怪的操作 = =

v4 = 0.0;
  v5 = qword_40C980;
  v6 = &MEMORY[0x40CBE8];
  v7 = a4[1];
  v8 = a4;
  v9 = a3;
  x1 = (*a4 - *(double *)0_01 + 1.0) / (*(double *)9_99 - *(double *)0_01 + 1.0);
  *a4 = x1;
  y1 = (v7 - *(double *)&0_03 + 1.0) / (*(double *)&9__99 - *(double *)&0_03 + 1.0);
  y = y1;
  a4[1] = y1;
  while ( 1 )
  {
    v13 = x1 * *((double *)v6 - 1);
    ++v5;
    v6 += 2;
    *(_QWORD *)&v14 = COERCE_UNSIGNED_INT64(y * *((double *)v6 - 2) + v13 + 0.0) ^ xmmword_409030;// change sign
    sub_4034D0((__int64)&qword_40CA10, (__int64)qword_40C980, v14, y1);// sigmoid
    *((double *)v5 - 1) = 1.0 / (v14 + 1.0);
    if ( &qword_40CA10 == v5 )
      break;
    x1 = *v8;
    y = v8[1];
  }
  result = 0LL;
  do
  {
    v16 = *(double *)&qword_40CD00[result] * *(double *)&qword_40C980[result];
    ++result;
    v4 = v4 + v16;
  }
  while ( result != 18 );
  v17 = v8[2];
  if ( v17 <= 1.0 || v17 >= 10.0 || (v18 = v8[3], v18 <= 1.0) || v18 >= 10.0 )
  {
    *(double *)qword_40CD00 = *(double *)qword_40CD00 * *(double *)qword_40CD00;
    *v9 = 10.0;
  }
  else
  {
    *v9 = v4 * (*(double *)&19_32 - *(double *)&0_26 + 1.0) + *(double *)&0_26 - 1.0;
  }
  return result * 8;
}

首先程序里硬编码了一些浮点数,用C语言搞一下得到真实值,标一下。然后现场学了一下神经网络,参考这篇文章
https://www.cnblogs.com/heaad/archive/2011/03/07/1976443.html
大概明白了这个程序实现了一个神经元,神经元中有一个二维权重向量{w, v},可以提取出来,将输入的两个浮点数x和y先进行一个预处理,然后生成净激活{x × wi + y × vi}向量,接着经过一个激活函数f得到向量z,最后将一个硬编码的输入向量和z相乘得到一个数。经过调试,发现f函数符合Sigmoid型函数。

 

得到数字之后做sprintf,判断是否为小于10的浮点数,并取整数位和小数前两位这三个数字,平方相加后开根号,判断是否大于15.5,以及之前的y的第3字节的低4bit是否为0.最后一个检验是检查x + y - f的绝对值是否小于0.003.

逆(bao)向(po)

x y的取值非常有限,写一个程序爆破:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>


 long long xx[] = 
 {
     0x0BFF0645E9156DBC1, 0x3FB5B59C6AE0004B,0x0BFE0FD9DEF0F5F9A, 0x3FE685E23E24E853,
0xBFBEDEBCA72F7512,0x0BFD40B39A1B3CB8C,0x0BFE87D3F640F203C, 0x3FD5B9DCAD3E9529,
0x3FDA27F983BCFDC3, 0x3FD62BE5D9589EAE,0x0BFE581B69A36B717, 0x3FE6801BBF527252,
0x3FDEAE2EA9FA99CC, 0x3FC290C00A49CF36,0x0BFE842DEACE9DB6E,0x0BFF30F05544464E8,
0x0BFE6EC1FDA490984,0x0BFC7C4E2F5A93E07,0x0BFD8D6B32E2FB6F9,0x0BFDC416F857C9468,
0x3FE7F90F71FEB8D9,0x0BFD2CC5C4EF8FBF4,0x0BFD1F8160A51CD2B,0x0BFE5202BE8B76C05,
0x0BFF23B46C97DC5A4,0x0BFD7E42B9359DDEB,0x0BFD7C90E0C010F65,0x0BFD48AAE09661ADC,
0x3FCD2D7C013B771C, 0x3FD2520DDF5608B2,0x0BFE4BF1ED4E7248A, 0x3FD5EBAD5FB98A18,
0x3FBA13DBE1D40BC8,0x0BFB123848B37921F,0x0BFE993D71BB7483C, 0x3FD1BB92E0D38D8F    
 };

 double * q = (double *)xx;

 long long yy[] =
{
  -4630103132371419281LL,
  4600232944741145390LL,
  -4623664845724579008LL,
  -4619646120402448712LL,
  4607355026434856585LL,
  4596128861265473190LL,
  4607190646444536679LL,
  4601659646545995648LL,
  -4620051764138102684LL,
  -4614531173946763955LL,
  4594888180182660529LL,
  -4615499524138853005LL,
  4598239803622968675LL,
  -4616289782979859051LL,
  4603682355018475170LL,
  4594542284310650225LL,
  4602848623156325133LL,
  4599049943557156486LL
};

double * r = (double *)yy;

double check(double x, double y)
{
    double m[18] = {0};

    x = (x + 0.99) / (10.98);
    y = (y + 0.97) / (10.96);
    //printf("%llx %llx\n", *(long long *)&x, *(long long *)&y);
    for (int i = 0; i < 18; i++)
    {
        m[i] = 1.0 / ( exp(-(x * q[2 * i] + y * q[2 * i + 1])) + 1.0);
        //printf("%llx\n", *(long long *)&m[i]);
    }
    double res = 0.0;
    for (int i = 0; i < 18; i++)
    {
        res += r[i] * m[i];
    }
    res = res * (19.32 - 0.26  + 1.00) + 0.26 - 1.0;
    return res;
}

double next_sqrt(double res)
{
    int bit1 = int(res);
    int bit2 = int(res * 10) % 10;
    int bit3 = int(res * 100) % 10; 
    //printf("%d %d %d", bit1, bit2, bit3);
    double z = sqrt(bit1 * bit1 + bit2 * bit2 + bit3 * bit3);
    //printf("%lf", z);
    return z;
}

int main()
{
    // 3FF0000000000000 - 4024000000000000
    for (long long x = 0x3FF1000000000000; x < 0x4024000000000000; x += 0x1000000000000)
    {
        for (long long y = 0x3FF1000000000000; y < 0x4024000000000000; y += 0x100000000000)
        {
            double x1 = *(double *)&x;
            double y1 = *(double *)&y;
            double z = check(x1, y1);
            if (z < 10.0 && next_sqrt(z) > 15.5 && fabs(x1 + y1 - z) < 0.003 )
            {
                printf("%llx %llx\n", x, y);
            }
        } 
    }
 }

得到X和Y的bytes

3ff1000000000000 4021e00000000000

按照要求重排一下得到Flag

F13FE02140

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

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