buu练题记录7-[网鼎杯 2020 青龙组]singal

0x00 查壳

首先拿到的是一个exe文件,所以先查壳,然后看看是32位还是64位的程序

image-20210417145819257

32位的程序,无壳。进入IDA分析:

0x01 IDA分析

image-20210417150023401

很容易就找到mian函数,逻辑简单,就一个函数。直接进入函数分析:

int __cdecl vm_operad(int *a1, int a2)
{
  int result; // eax
  char v3[100]; // [esp+13h] [ebp-E5h]
  char v4[100]; // [esp+77h] [ebp-81h]
  char v5; // [esp+DBh] [ebp-1Dh]
  int v6; // [esp+DCh] [ebp-1Ch]
  int v7; // [esp+E0h] [ebp-18h]
  int v8; // [esp+E4h] [ebp-14h]
  int v9; // [esp+E8h] [ebp-10h]
  int v10; // [esp+ECh] [ebp-Ch]

  v10 = 0;
  v9 = 0;
  v8 = 0;
  v7 = 0;
  v6 = 0;
  while ( 1 )
  {
    result = v10;
    if ( v10 >= a2 )
      return result;
    switch ( a1[v10] )
    {
      case 1:                                   // 调用到1的时候就完成一个v4值得产生
        v4[v7] = v5;
        ++v10;
        ++v7;
        ++v9;
        break;
      case 2:
        v5 = a1[v10 + 1] + v3[v9];              // a1当前值得下一个值与v3当前值的和
        v10 += 2;
        break;
      case 3:
        v5 = v3[v9] - LOBYTE(a1[v10 + 1]);      // v3的当前值减去a1下一个值
        v10 += 2;
        break;
      case 4:
        v5 = a1[v10 + 1] ^ v3[v9];              // 异或
        v10 += 2;
        break;
      case 5:
        v5 = a1[v10 + 1] * v3[v9];              // 相乘
        v10 += 2;                               // 2,3,4,5下的运算,均为v10 += 2,既他们下一个的数的值即使在运算步骤的取值范围内,也不作为运算步骤
        break;
      case 6:
        ++v10;
        break;
      case 7:
        if ( v4[v8] != a1[v10 + 1] )            // 之前产生的v4的值和a1中为7的值的下一个值比较
        {
          printf("what a shame...");
          exit(0);                              // 不同则停止程序
        }
        ++v8;
        v10 += 2;
        break;
      case 8:
        v3[v6] = v5;                            // 将当前运算的暂时的结果覆盖到当前的v3进行接来下的运算,直到调用1,产生新的v4,取下一个v3进入运算
        ++v10;
        ++v6;
        break;
      case 10:
        read(v3);                               // 写入v3,既将input传入v3
        ++v10;
        break;
      case 11:
        v5 = v3[v9] - 1;                        // 减1
        ++v10;
        break;
      case 12:
        v5 = v3[v9] + 1;                        // 加1
        ++v10;
        break;
      default:                                  // 大于12的值不作为运算方法,但参与其他的的运算的调用。
        continue;
    }
  }
}

通过分析read函数可知,输入的字符长度为15个

image-20210417152045868

在main函数中可知,vm_operad函数的a1是传入的v4,而v4则是cpy的dword_403040。所以我们直接查看dword_403040的值:

image-20210417152451917

将数据提取出来然后处理一下:

10,				//输入
4,16,8,3,5,1,	 //第1个数
4,32,8,5,3,1,
3,2,8,11,1,		
12,8,4,4,1,
5,3,8,3,33,1,
11,8,11,1,
4,9,8,3,32,1,
2,81,8,4,36,1,	 //第8个数
12,8,11,1,
5,2,8,2,37,1,	
2,54,8,4,65,1,
2,32,8,5,1,1,	//第一个1它前面是5,所以它没有被调用,后面的1才产生了一个v4
5,3,8,2,37,1,
4,9,8,3,32,1,
2,65,8,12,1,	//第15个数
7,34,7,63,7,52,7,50,7,114,7,51,7,24,7,-89,7,49,7,-15,7,40,7,-124,7,-63,7,30,7,122  //15次效验

0x02 exp

exp1

起初是写了一个爆破的exp,因为当时没有弄的太明白:

#include<stdio.h>
#include<string.h>
#include<windows.h>

char a1[] = {10,4,16,8,3,5,1,4,32,8,5,3,1,3,2,8,11,1,12,8,4,4,1,5,3,8,3,33,1,11,8,11,1,4,9,8,3,32,1,2,81,8,4,36,1,12,8,11,1,5,2,8,2,37,1,2,54,8,4,65,1,2,32,8,5,1,1,5,3,8,2,37,1,4,9,8,3,32,1,2,65,8,12,1,0};
unsigned char a2[] = {34,63,52,50,114,51,24,-89,49,-15,40,-124,-63,30,122,0};
int v10 = 0,v8 = 0,v7 = 0,v9 = 0,v6 = 0;
unsigned char v5,flag;

int crypt(int F,int S){
	v10 = S;
	while(1){
		switch ( a1[v10] ){
			case 0:
				exit(0);
			case 1:
		        return v5;
		    case 2:
		        v5 = a1[v10 + 1] + F;
		        v10 += 2;
		        break;
		    case 3:
		        v5 = F - (a1[v10 + 1]);
		        v10 += 2;
		        break;
		    case 4:
		        v5 = a1[v10 + 1] ^ F;
		        v10 += 2;
		        break;
		    case 5:
		        v5 = a1[v10 + 1] * F;
		        v10 += 2;
		        break;
		    case 6:
		        ++v10;
		        break;
		    case 7:
		        v10 += 2;
		        break;
		    case 8:
		        F = v5;
		        ++v10;
		        break;
		    case 10:
		        ++v10;
		        break;
		    case 11:
		        v5 = F - 1;
		        ++v10;
		        break;
		    case 12:
		        v5 = F + 1;
		        ++v10;
		        break;
		    default:
		        continue;
		}
	}
}

int main(){
	int V10 = 0 ,i = 0;
	while(1){	//硬爆破,唉,就是玩!
		for(flag = 1;flag<=122;flag++){
			int Crypt = crypt(flag,V10);
			if(Crypt == a2[i]){
				printf("%c",flag);
				i++;
				for(V10;a1[V10] != 1;V10++);
					V10++;			//匹配一个值进入下一个值的操作数段开头
				if(a1[V10] == 1)	//两个1的地方,往后跳一下
					V10++;
			}
		}
	}
}

exp2

边写笔记边把自己给弄明白了,同时也是为了更好的理解这个题,所以这里又写了一个逆算法和过程的exp:

#include<stdio.h>
#include<string.h>

char a1[] = {10,4,16,8,3,5,1,4,32,8,5,3,1,3,2,8,11,1,12,8,4,4,1,5,3,8,3,33,1,11,8,11,1,4,9,8,3,32,1,2,81,8,4,36,1,12,8,11,1,5,2,8,2,37,1,2,54,8,4,65,1,2,32,8,5,1,1,5,3,8,2,37,1,4,9,8,3,32,1,2,65,8,12,1,0};
unsigned char a2[] = {34,63,52,50,114,51,24,-89,49,-15,40,-124,-63,30,122,0};
int v10 = strlen(a1) - 1,v8 = 14,v7 = 0,v9 = 15,v6 = 0;
unsigned char v5 = 0,flag[16];

int main(){
	memset(flag,0,16);
	while(v10 >= 0){
		if(a1[v10-1] <= 5 && a1[v10-1] >= 2){	//这里是跳过非操作数,选出操作步骤 
			if(a1[v10-2] <= 5 && a1[v10-2] >= 2);
			else
				v10 --;
		}
		switch ( a1[v10] ){
			case 1:
		        v5 = a2[v8];
		        v9--;
		        v8--;
		        v10--;
		        break;
		    case 2:
		        flag[v9] = v5 - a1[v10 + 1];
		        v10--;
		        break;
		    case 3:
		        flag[v9] = v5 + (a1[v10 + 1]);
		        v10--;
		        break;
		    case 4:
		        flag[v9] = a1[v10 + 1] ^ v5;
		        v10--;
		        break;
		    case 5:
		        flag[v9] = v5 / a1[v10 + 1];
		        v10--;
		        break;
		    case 6:
		        --v10;
		        break;
		    case 8:
		        v5 = flag[v9];
		        --v10;
		        break;
		    case 10:
		        printf("%s",flag);
		        --v10;
		        break;
		    case 11:
		        flag[v9] = v5 + 1;
		        --v10;
		        break;
		    case 12:
		        flag[v9] = v5 - 1;
		        --v10;
		        break;
		    default:
		    	v10 -= 1;
		        break;
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值