我讨厌数学 - WHCTF - 2016 - Reverse

下载链接

这题的逆向部分比较容易,细节略过,只给出结果。

要求用户输入flag,长度为27字符,程序将其与9个1一起排成6*6的矩阵:

. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . 1 1 1
1 1 1 1 1 1

注意,这里的.表示用户的输入,而1表示数字1不是字符’1’。

假设这个6*6矩阵为A,程序计算矩阵A*Trans(A),判断与给定的矩阵是否相等(Trans表示转置)。

从内存中copy之后得到原矩阵为(后面记为B):

第一列第二列第三列第四列第五列第六列
7376762102489105537237336663
6210255344417664507230247560
4891041766368433471728867445
5537245072347174506928239503
3733630247288672823939900348
6635604455033486

该矩阵第i行j列的值 == A的第i行与第j行分别相乘,然后相加。

本来是不可能直接解回去的,但是我们有很多限制条件:

  • A的前27个数都是介于32~127的整数。
  • 不是36个元素都不知道,我们已经知道后面9个是1。
  • 第1行的元素恰好是”whctf{“。

第三条靠猜,但是验证起来非常容易:

>>> b="whctf{"
>>> l=list()
>>> for i in b:
    l.append(ord(i))
>>> l
[119, 104, 99, 116, 102, 123]
>>> sum(l)
663
>>> sum([i*i for i in l])
73767

接下来选取第5行作为突破口。第5行应该是这样的形式:

. . } 1 1 1

利用B(5,1)、B(5,6)的值可以轻易推出第5行的内容为:
// B(5,1)表示矩阵B的第5行第1列的元素,下同

t h } 1 1 1

剩下几行没有想到比较好的思路,决定采用逐行爆破。建议用C语言提升效率。
比如第二行的爆破代码如下:

#include<stdio.h>
#define ROW1 62102
#define ROW5 30247
#define ROW6 560
#define ROWSELF 55344

int buf[6];
char out[10]={0};
int p[]={119, 104, 99, 116, 102, 123};  //"whctf{"
int q[]={116,104,125,1,1,1};            //第5行内容
void test()
{
    int sum=0;
    int i;
    for(i=0;i<6;i++)
        sum+=buf[i]*buf[i];
    if(sum!=ROWSELF)          //判断平方和是否与B(2,2)相等
        return;
    sum=0;
    for(i=0;i<6;i++)
        sum+=p[i]*buf[i];
    if(sum!=ROW1)          //判断与第1行相乘相加是否与B(2,1)相等       
        return;
    sum=0;
    for(i=0;i<6;i++)
        sum+=q[i]*buf[i];
    if(sum!=ROW5)          //判断与第5行相乘相加是否与B(2,5)相等
        return;
    for(i=0;i<6;i++)
        out[i]=buf[i];
    printf("%s\n",out);     //通过上面检验条件的可以输出了
}

void burp(int m)
{
    int k,i;
    if(m==5)
    {
        k=ROW6;              //利用与第6行相乘相加的值与B(2,6)相等
        for(i=0;i<5;i++)    //可以求出第2行各个元素的和
            k-=buf[i];      //因此实际的burp相当于是5次方而不是6次方
        buf[5]=k;           //从而节约不少时间
        if(k<0x7f&&k>=0x20)
            test();
    }
    else
    {
        for(i=0x20;i<0x7f;i++)
        {
            buf[m]=i;
            burp(m+1);
        }
    }

}

int main()
{
    burp(0);
}

每行都写了份代码,本来是打算发给队友并行计算,后来发现修改代码的过程中就差不多能跑完上一份代码了。

最后把2、3、4行跑出来,拼起来得到flag:whctf{Y0u_ar3_g00d_a7_m4th}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值