[安洵杯 2019]game writeup

每天一道re

Exeinfo PE查壳,可以用Linux打开

用kali打开,得到关键语句

 用ida打开,找到main函数F5反编译

int __cdecl main(int argc, const char **argv, const char **envp)
{
  signed int v3; // eax
  unsigned int v4; // ST38_4
  __int64 v5; // rsi
  signed int v7; // [rsp+2Ch] [rbp-54h]
  char v8; // [rsp+40h] [rbp-40h]
  int v9; // [rsp+78h] [rbp-8h]
  int v10; // [rsp+7Ch] [rbp-4h]

  v9 = 0;
  printf("input your flag:", argv, envp);
  gets(&v8);
  v10 = general_inspection((int (*)[9])sudoku);
  v7 = -1804515313;
  while ( 1 )
  {
    while ( 1 )
    {
      while ( v7 == -2071121728 )
      {
        v4 = blank_num((int (*)[9])sudoku);
        v5 = mem_alloc(v4);
        trace(sudoku, v5, v4);
        check((int (*)[9])sudoku);
        check1(&v8);
        check3(&v8);
        v9 = 0;
        v7 = -303742386;
      }
      if ( v7 != -1804515313 )
        break;
      v3 = -2071121728;
      if ( v10 )
        v3 = 664169471;
      v7 = v3;
    }
    if ( v7 == -303742386 )
      break;
    if ( v7 == 664169471 )
    {
      printf("error");
      check((int (*)[9])sudoku);
      v9 = 0;
      v7 = -303742386;
    }
  }
  return v9;
}

输入的flag传入到v8,直接跟踪v8 ,发现传入了check1和check3,查看check1,用了ollvm,OLLVM(Obfuscator-LLVM)是瑞士西北应用科技大学安全实验室于2010年6月份发起的一个项目,这个项目的目标是提供一个LLVM编译套件的开源分支,能够通过代码混淆和防篡改,增加对逆向工程的难度,提供更高的软件安全性。

来自(47条消息) OLLVM分析_chrisnotfound-CSDN博客_ollvm

其实慢慢分析不断跟踪v10的值,就很快分析出了他其实就是三层加密操作

 接下来就是check3,check3又套了一层check2加密操作

__int64 __fastcall check3(char *a1)
{
  __int64 result; // rax
  signed int v2; // eax
  signed int v3; // [rsp+28h] [rbp-18h]
  int v4; // [rsp+3Ch] [rbp-4h]

  v4 = check2(a1);
  v3 = 16123822;
  while ( 1 )
  {
    while ( v3 == 16123822 )
    {
      v2 = 1478060410;
      if ( !v4 )
        v2 = 1274132590;
      v3 = v2;
    }
    result = (unsigned int)(v3 - 824643665);
    if ( v3 == 824643665 )
      break;
    if ( v3 == 1274132590 )
    {
      v3 = 824643665;
      printf("error!\n");
    }
    else if ( v3 == 1478060410 )
    {
      v3 = 824643665;
      printf("you get it!\n");
    }
  }
  return result;
}

根据动态调试可以知道flag不正确会返回1,正确即为零,然后check3就会输出“you get it!”

看看check3,也是和check1同样的分析方法

 第二层:D0g3[9 * v15 + v14] ==0时,将v16给了二维数组dog3,有点绕,我用了动态调试的方法,一开始查看dog3的值:

不对F8,得到

 再去与v16的值进行对比,发现是v16的值给了dog3中零的位置 

然后就密码核对用到的sudoku,查看main的函数发现有对sudoku进行操作,直接动态调试得到结果

最后的脚本为:

#include<stdio.h>
int main()
{           
	int a[81]={1,4,5,3,2,7,6,9,8,8,3,9,6,5,4,1,2,7,6,7,2,8,1,9,5,4,3,4,9,6,1,8,5,3,7,2,2,1,8,4,7,3,9,5,6,7,5,3,2,9,6,4,8,1,3,6,7,5,4,2,8,1,9,9,8,4,7,6,1,2,3,5,5,2,1,9,3,8,7,6,4};
	int P[81]={1,0,5,3,2,7,0,0,8,8,0,9,0,5,0,0,2,0,0,7,0,0,1,0,5,0,3,4,9,0,1,0,0,3,0,0,0,1,0,0,7,0,9,0,6,7,0,3,2,9,0,4,8,0,0,6,0,5,4,0,8,0,9,0,0,4,0,0,1,0,3,0,0,2,1,0,3,0,7,0,4};
	int R[40];//输入的flag 
	int o;
	int L=0;
	int temp;
	
	for(int i=0;i<81;i++)
    {
  	  if(P[i]==0)
  	  {R[L]=a[i]+232084296-232084248;L++;} //得到flag的密码表  
    }
  for (int i = 0; i <40; i++) { temp = R[i] + 20; temp = temp & 0xf3 | ~temp & 0xc; R[i] = temp; }
  //前后两个置换 
   for(int i=0;i<40;i=i+2)
   {o = R[i]; R[i] = R[i+1]; R[i+1] = o;}
  //前后两个部分置换
  int g=40>>1;
  for(int i=0;i<40>>1;i++,g++)
  {o = R[i]; R[i] = R[g]; R[g] = o;}
  for(int i=0;i<40;i++)
  {printf("%c",R[i]);}
   
} 

 反思,在check2第二层加密中,没有想到用动态分析,导致静态分析错误,又浪费了时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值