BUUCTF [网鼎杯 2020 青龙组]singal

两种做法

算法逆向

关键就是将正向加密时v9的值找出来 逆向解密时反向即可(在case里面操作v9很容易错)
还有就是加密解密有些语句前后左右要对调

#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
signed main(){
	unsigned char unk_403040[512] = {
    0x0A, 0x00, 0x00, 0x00, 
	0x04, 0x00, 0x00, 0x00, 
	0x10, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
    0x03, 0x00, 0x00, 0x00, 
	0x05, 0x00, 0x00, 0x00, 
	0x01, 0x00, 0x00, 0x00, 
	0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
	0x05, 0x00, 0x00, 0x00, 
	0x03, 0x00, 0x00, 0x00, 
    0x01, 0x00, 0x00, 0x00, 
	0x03, 0x00, 0x00, 0x00, 
	0x02, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
    0x0B, 0x00, 0x00, 0x00, 
	0x01, 0x00, 0x00, 0x00, 
	0x0C, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
    0x04, 0x00, 0x00, 0x00, 
	0x04, 0x00, 0x00, 0x00, 
	0x01, 0x00, 0x00, 0x00, 
	0x05, 0x00, 0x00, 0x00, 
    0x03, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
	0x03, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 
    0x01, 0x00, 0x00, 0x00, 
	0x0B, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
	0x0B, 0x00, 0x00, 0x00, 
    0x01, 0x00, 0x00, 0x00, 
	0x04, 0x00, 0x00, 0x00, 
	0x09, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
    0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x01, 0x00, 0x00, 0x00, 
	0x02, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
	0x04, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 
    0x01, 0x00, 0x00, 0x00, 
	0x0C, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
	0x0B, 0x00, 0x00, 0x00, 
    0x01, 0x00, 0x00, 0x00, 
	0x05, 0x00, 0x00, 0x00, 
	0x02, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
    0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 
	0x01, 0x00, 0x00, 0x00, 
	0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
	0x04, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 
    0x01, 0x00, 0x00, 0x00, 
	0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
    0x05, 0x00, 0x00, 0x00, 
	0x01, 0x00, 0x00, 0x00, 
	0x01, 0x00, 0x00, 0x00, 
	0x05, 0x00, 0x00, 0x00, 
    0x03, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
	0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 
    0x01, 0x00, 0x00, 0x00, 
	0x04, 0x00, 0x00, 0x00, 
	0x09, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
    0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
	0x01, 0x00, 0x00, 0x00, 
	0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 
	0x08, 0x00, 0x00, 0x00, 
	0x0C, 0x00, 0x00, 0x00, 
	0x01, 0x00, 0x00, 0x00, 
    0x07, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 
	0x07, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 
    0x07, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 
	0x07, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 
    0x07, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 
	0x07, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 
    0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 
	0x07, 0x00, 0x00, 0x00, 0xA7, 0xFF, 0xFF, 0xFF, 
    0x07, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 
	0x07, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF, 
    0x07, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 
	0x07, 0x00, 0x00, 0x00, 0x84, 0xFF, 0xFF, 0xFF, 
    0x07, 0x00, 0x00, 0x00, 0xC1, 0xFF, 0xFF, 0xFF, 
	0x07, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 
    0x07, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00
};
	unsigned int a1[114] = {
	    0x0000000A, 0x00000004, 0x00000010, 0x00000008, 0x00000003, 0x00000005, 0x00000001, 0x00000004,
	    0x00000020, 0x00000008, 0x00000005, 0x00000003, 0x00000001, 0x00000003, 0x00000002, 0x00000008,
	    0x0000000B, 0x00000001, 0x0000000C, 0x00000008, 0x00000004, 0x00000004, 0x00000001, 0x00000005,
	    0x00000003, 0x00000008, 0x00000003, 0x00000021, 0x00000001, 0x0000000B, 0x00000008, 0x0000000B,
	    0x00000001, 0x00000004, 0x00000009, 0x00000008, 0x00000003, 0x00000020, 0x00000001, 0x00000002,
	    0x00000051, 0x00000008, 0x00000004, 0x00000024, 0x00000001, 0x0000000C, 0x00000008, 0x0000000B,
	    0x00000001, 0x00000005, 0x00000002, 0x00000008, 0x00000002, 0x00000025, 0x00000001, 0x00000002,
	    0x00000036, 0x00000008, 0x00000004, 0x00000041, 0x00000001, 0x00000002, 0x00000020, 0x00000008,
	    0x00000005, 0x00000001, 0x00000001, 0x00000005, 0x00000003, 0x00000008, 0x00000002, 0x00000025,
	    0x00000001, 0x00000004, 0x00000009, 0x00000008, 0x00000003, 0x00000020, 0x00000001, 0x00000002,
	    0x00000041, 0x00000008, 0x0000000C, 0x00000001, 0x00000007, 0x00000022, 0x00000007, 0x0000003F,
	    0x00000007, 0x00000034, 0x00000007, 0x00000032, 0x00000007, 0x00000072, 0x00000007, 0x00000033,
	    0x00000007, 0x00000018, 0x00000007, 0xFFFFFFA7, 0x00000007, 0x00000031, 0x00000007, 0xFFFFFFF1,
	    0x00000007, 0x00000028, 0x00000007, 0xFFFFFF84, 0x00000007, 0xFFFFFFC1, 0x00000007, 0x0000001E,
	    0x00000007, 0x0000007A
	};
	
int a2 = 114;
  int result; // eax
  char Str[200]; // [esp+13h] [ebp-E5h] BYREF
  unsigned char v4; // [esp+DBh] [ebp-1Dh]
  int v5; // [esp+DCh] [ebp-1Ch]
  int v6; // [esp+E0h] [ebp-18h]
  int v7; // [esp+E4h] [ebp-14h]
  int v8; // [esp+E8h] [ebp-10h]
  int v9; // [esp+ECh] [ebp-Ch]

  v9 = 0;
  v8 = 0;
  v7 = 0;
  v6 = 0;
  v5 = 0;
  while ( 1 )                                   // OpCode:unk_403040   a2:114
  {
    result = v9;
    if ( v9 >= a2 )
      break;
//      cout<<result<<",";
    switch ( a1[v9] )
    {
      case 1:
        Str[v6 + 100] = v4;                     // 给Str[100~114]赋值
        ++v9;
        ++v6;
        ++v8;
        break;
      case 2:
        v4 = a1[v9 + 1] + Str[v8];
        v9 += 2;
        break;
      case 3:
        v4 = Str[v8] - LOBYTE(a1[v9 + 1]);
        v9 += 2;
        break;
      case 4:
        v4 = a1[v9 + 1] ^ Str[v8];
        v9 += 2;
        break;
      case 5:
        v4 = a1[v9 + 1] * Str[v8];
        v9 += 2;
        break;
      case 6:
        ++v9;
        break;
      case 7:
//        if ( Str[v7 + 100] != OpCode[v9 + 1] )
//        {
//          printf("what a shame...");
//          exit(0);
//        }
        ++v7;
        v9 += 2;
        break;
      case 8:
        Str[v5] = v4;
        ++v9;
        ++v5;
        break;
      case 10:
//        read(Str);
        ++v9;
        break;
      case 11:
        v4 = Str[v8] - 1;
        ++v9;
        break;
      case 12:
        v4 = Str[v8] + 1;
        ++v9;
        break;
      default:
        continue;
    }
}
	cout<<v5<<" "<<v6<<" "<<v7<<" "<<v8<<" "<<v9<<"\n\n\n";
	//op[]是代码加密的正向指令流(每次v9的值)
	unsigned int op[]={0,1,3,4,6,7,9,10,12,13,15,16,17,18,19,20,22,23,25,26,28,29,30,31,32,33,35,36,38,39,41,42,44,45,46,47,48,49,51,52,54,55,57,58,60,61,63,64,66,67,69,70,72,73,75,76,78,79,81,82,83,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112};
	unsigned int data[15] = { 0X22, 0X3F, 0X34, 0X32, 0X72, 0X33, 0X18, 0XFFFFFFA7, 0X31, 0XFFFFFFF1, 0X28, 0XFFFFFF84, 0XFFFFFFC1, 0X1E, 0X7A };
	unsigned char buf[100];
	unsigned char flag[100];
//	v9 = 112;
  	v8 = 15;
  	v7 = 15;
  	v6 = 15;
  	v5 = 15;
  	int k=75;
  	while (k>=0)                                   // OpCode:unk_403040   a2:114
  	{
//  		cout<<v9<<"\n";
    	int v9 = op[k];
    	switch(a1[v9]){
    		case 1:
    			v6--;
    			v8--;
//    			v9--;
    			v4 = buf[v6];
    			break;
    		case 2:
//    			v9 -= 2;
    			flag[v8] = v4 - a1[v9+1];
    			break;
    		case 3:
//    			v9 -= 2;
    			flag[v8] = v4 + a1[v9+1];
    			break;
    		case 4:
//    			v9 -= 2;
    			flag[v8] = v4 ^ a1[v9+1];
    			break;
    		case 5:
//    			v9 -= 2;
    			flag[v8] = v4 / a1[v9+1];
    			break;
    		case 6:
//    			v9--;
    			break;
    		case 7:
//    			v9 -= 2;
    			v7--;
				buf[v7] = a1[v9+1];
				break;
    		case 8:
    			v5--;
//    			v9--;
    			v4 = flag[v5];
    			break;
    		case 10:
    			cout<<"Start!\n\n";
//				v9--;
				break;
    		case 11:
//    			v9--;
    			flag[v8] = v4 + 1;
    			break;
    		case 12:
//    			v9--;
    			flag[v8] = v4 - 1;
    			break;
    		default:
    			continue;
		}
		k--;
	}
	for(int i=0;i<15;i++)
		cout<<flag[i];
	return 0;
}

angr库求解

import angr
project = angr.Project('signal.exe') 	#创建项目,加载二进制文件
state = project.factory.entry_state()	#创建state
sim = project.factory.simgr(state)		#创建sim
sim.explore(find=0x40175e,avoid=0x4016e6) # 希望到达的和避免的分支
if sim.found:
    res = sim.found[0]
    res = res.posix.dumps(0)
    print("[+] Success! Solution is: {}".format(res.decode("utf-8")))

这里的0x40175e对应的vm_operad函数最后返回result的地方(也就是全部跑完) 0x4016e6对应的What a shame 失败(这里有个疑惑 为什么只能选择0x4016e6 尝试发现就算选择前面的if处的地址都跑不出结果 为什么呢???)
oh我知道了。。。 它if判断的地址和后面shame的不是连续的。。。
将signal.exe和.py放在同一个文件夹下 Linux运行
结果:
image

posted @ 2023-10-12 22:21  N0zoM1z0  阅读(32)  评论(0编辑  收藏  举报