'); }

2021羊城杯_DeltX


直接打开就能看到伪代码,逐步分析

开始判断是否加上了flag外壳,并判断了长度

  Input = 0i64;
  v170 = 0i64;
  v171 = 0i64;
  sub_140001020("Input your flag here:\r\n", argv, envp);
  sub_140001080("%46s", (const char *)&Input);
  if ( (_BYTE)Input != 'S'
    || *(_WORD *)((char *)&Input + 1) != 'na'
    || *(_DWORD *)((char *)&Input + 3) != 'roFg'
    || BYTE7(Input) != '{'
    || BYTE8(v171) != '}' )                     // SangFor{******************}
  {                                             // 动调确定len=41
    goto LABEL_155;                             // Error
  }

长度判断需要在汇编层面看(最开始动调的时候,没有注意长度问题,输入任意长度的值,在套了正确外壳的情况下,依旧会跳转到LABEL_155),仔细看判断{,与}之间判断的值长度,就可以知道具体输入了多少值

image-20210918214510465

然后进行了一大堆的值进行

 v5 = 0;
  I = 0i64;
  while ( 1 )                                   // 能输入的值:[0-9][A-Z]
  {
    v7 = *((char *)&Input + I + 8);
    if ( (unsigned __int8)(*((_BYTE *)&Input + I + 8) - '0') > 9u )
      break;
    v8 = v5 - 0x30;
LABEL_11:
    ++I;
    v5 = 16 * (v7 + v8);
    if ( I >= 4 )                               // 将四个字符转换成十六进制。比如说输入1234,转换成0x1234
    {
      v9 = v5 >> 4;
      v10 = 1;
      goto LABEL_14;
    }
  }
  if ( (unsigned __int8)(v7 - 'A') <= 5u )
  {
    v8 = v5 - '7';
    goto LABEL_11;
  }

吐槽一下,明明可以写函数或者循环实现这个操作,但是它就是要一个一个来写….后面判断也是….

image-20210918215816924

image-20210918215840421

然后两两数字为一组,进行运算,并将运算后的值和对应值比较,类似于解二元一次方程。

这里我是直接动调看输出值和两个输入值有什么关联,多次尝试得出关系,并没有仔细看内部的位运算,理论上可以直接模拟代码获取两个输入值

#两者关系
flag0*flag1=num1
flag0-flag1=num2

搓脚本:

def Save(mul,sub):
    for a in range(0xffff):
        b=(a-(sub))&0xffff
        if(a*b==mul):
            print("%X%X"%(a,b),end="")
if __name__=="__main__":
    mul=[0x249E15C5,0x34C7EAE2,0x637973BA,0xE5FD104]
    sub=[0xFFFF59BC,0x216B,0x819D,0x9393]
    print("SangFor{",end="")
    for i in range(len(mul)):
        Save(mul[i],sub[i])
    print("}")

flag:

SangFor{2C7BD2BF862564BAED0B6B6EA94F15BC}

image-20210918220729796


  目录