资讯详情

[XCTF-Reverse] 54-57

只能说开卷有益,至少比闭卷好。

54,easyCpp

这是一个无法理解的程序,基本上是通过猜测

该程序首先读入16个数字,然后生成斐波那契数列16个项目,一翻神操作后与数列成功输出。

调用三个函数:transform,accumulate和copy_if。

第一个大根可以理解,后面的数减是第一个...

  for ( i = 0; i <= 15;   i )   {     scanf("%d", &v35[4 * i], v25);     std::vector<int,std::allocator<int>>::push_back(&v29, &v35[4 * i]);// 输入16个整数   }   for ( j = 0; j <= 15;   j )   {     LODWORD(v34) = fib(j);     std::vector<int,std::allocator<int>>::push_back(&v28, &v34);// 斐波那契前16项   }   std::vector<int,std::allocator<int>>::push_back(&v30, v35);// 第一个输入数   v9 = std::back_inserter<std::vector<int,std::allocator<int>>>(&v30);   v10 = std::vector<int,std::allocator<int>>::end(&v29);   v34 = std::vector<int,std::allocator<int>>::begin(&v29);   v11 = __gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator (&v34, 1LL);   transform(v11, v10, v9, (__int64)v35);   std::vector<int,std::allocator<int>>::vector(&v33, v10, v12);   v13 = std::vector<int,std::allocator<int>>::end(&v30);   v14 = std::vector<int,std::allocator<int>>::begin(&v30);   std::accumulate<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,std::vector<int,std::allocator<int>>,main::{lambda(std::vector<int,std::allocator<int>>,int)#2}>(     (__int64)&v34,     v14,     v13,     (__int64)&v33,     v15,     v16,     v4);   std::vector<int,std::allocator<int>>::operator=(&v31, &v34);   std::vector<int,std::allocator<int>>::~vector(&v34);   std::vector<int,std::allocator<int>>::~vector(&v33);   if ( (unsigned __int8)std::operator!=<int,std::allocator<int>>(&v31, &v28) )   {     puts("You failed!");     exit(0);   }   v17 = std::back_inserter<std::vector<int,std::allocator<int>>>(&v32);   v18 = std::vector<int,std::allocator<int>>::end(&v29);   v19 = std::vector<int,std::allocator<int>>::begin(&v29);   std::copy_if<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,std::back_insert_iterator<std::vector<int,std::allocator<int>>>,main::{lambda(int)#3}>(     v19,     v18,     v17,     v20,     v21,     v22,     v3);   puts("You win!");   printf("Your flag is:flag{", v18, v25);   v33 = std::vector<int,std::allocator<int>>::begin(&v32);   v34 = std::vector<int,std::allocator<int>>::end(&v32);   while ( (unsigned __int8)__gnu_cxx::operator!=<int *,std::vector<int,std::allocator<int>>>(&v33, &v34) )   {     v23 = (unsigned int *)__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator*(&v33);     std::ostream::operator<<(&std::cout, *v23);     __gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator  (&v33);   }   putchar(125);

然后开始猜测,先输入一个序列,然后在每个第1函数和2函数后下断点(如果运行成功,就会产生结果,所以不需要猜第3个)

gdb-peda$ r Starting program: /home/shi/rev/easyCpp  1 2 4 5 6 8 10 15 11 19 20 33 44 55 66 77   从结果来看,加上第一个数字 gdb-peda$ x/16wd 0x618330 0x618330: 1 2 4 5 0x618340: 6 8 10 15 0x618350: 11 19 20 33 0x618360: 44 55 66 77 gdb-peda$ x/2gx $rsp 0x70 0x7fffffffdef0: 0x00000000006183d0 0x0000000000618410 gdb-peda$ x/16wd 0x6183d0 0x6183d0: 1 3 5 6 0x6183e0: 7 9 11 16 0x6183f0: 12 20 21 34 0x618400: 45 56 67 78  第二个函数后断点 gdb-peda$ b *0x400fe8 Breakpoint 2 at 0x400fe8  只是反向原序列 gdb-peda$ x/2gx $rsp 0xf0 0x7fffffffdf70: 0x00000000006185a0 0x00000000006185e0 gdb-peda$ x/20wd 0x6185a0 0x6185a0: 78 67 56 45 0x6185b0: 34 21 20 12 0x6185c0: 16 11 9 7 0x6185d0: 6 5 3 1 

通过观察运行前后的数据,可以确定第一个函数是将后面的数添加到第一个数,第二个函数是逆序,结果是序列前16项

#fib fib = [1,1] [fib.append(fib[-1] fib[-2]) for i in range(14)]  fib2 = fib[::-1] for i in range(1,16):     fib2[i] -= fib2[0]  print(fib) print(fib2)

然后输入正确的数据得到结果

~/rev$ ./easyCpp  987 -377 -610 -754 -843 -898 -932 -953 -966 -974 -979 -982 -984 -985 -986 -986 You win! Your flag is:flag{987-377-843-953-979-985}

55,XCTF 3rd-NJCTF-2017_echo-server

这是个不断patch问题,但是给出的附件不能运行,所以没有。

ida看到call或者jmp后面的地址是红色的,基本上是用代码错位。

((void (*)(void))((char *)&loc_80487C1   3))();

这个位置的前面c1位置1个字节patch掉后边是leave;ret函数正常

第2处是080487F3,改为nop,后面的程序显示输入和8048817 检查正确,这里的代码实际上是字符串,用D显示 F1@gA

这个操作只能在第三个地方知道(是运行不了)

.text:08048848                 mov     eax, ds:dword_804A088
.text:0804884D                 test    eax, eax
.text:0804884F                 jz     short loc_8048866

由于这里被固定置成1,所以不会运行到8048866所以这里可以在gdb里改也可以patch 804a088或者把jz改成jnz或者jmp

结果可以网上搜

56,tinyctf-2014_What-does-this-button-do

一开始没有扩展名看头以为是压缩包,解开得到classes.dex(应该是apk,不过最后也得处理dex),把文件转jar然后jd-gui打开,看到一串flag开头的数字,然后就是它了(坑!提交时要去包裹)

bytes([102,108,97,103,123,119,52,110,110,52,95,106,52,114,95,109,121,95,100,51,120,125])
#classes.dex -> jar
#ctf.crackme.FlagActivity 有代码flag开头
#flag{w4nn4_j4r_my_d3x}
#提交去包裹 w4nn4_j4r_my_d3x

57,csaw-ctf-2016-quals_tar-tar-binks

给了一个flag.tar和一个链接库(dylib格式,没见过,但ida认识)

里边有数不清的函数,主要在_sub_102*这块

flag.tar时一堆0然后是4个一组的16进制数,根据这个找%04X 这是从网上搜到的,其实生成16进制方法很多,这个方法运行是最慢的。如果不是出题人估计不大容易想到。

根据这个,看加密方法,sub_101数组是加密好的数据,生成安的是sub_1023458,是把一个序列每3个成一组输出

unsigned int *__fastcall sub_1023458(_DWORD *a1)    //生成sub_101数组输出
{
  unsigned int *result; // rax
  int v2; // ST04_4
  int v3; // esi

  result = sub_101;
  v2 = *a1 + 40 * a1[1] + 1600 * a1[2];
  v3 = posi++;
  sub_101[v3] = v2;
  return result;
}

这个序列是由sub_1023457生成,计入原码用sub_1023456加密后,够3个就输出一下

__int64 __fastcall sub_1023457(char *a1, int a2)
{
  int v2; // eax
  char *v3; // rax
  unsigned int v5; // [rsp+4h] [rbp-2Ch]
  signed int v6; // [rsp+8h] [rbp-28h]
  int v7; // [rsp+Ch] [rbp-24h]
  char *v8; // [rsp+10h] [rbp-20h]
  int v9[3]; // [rsp+1Ch] [rbp-14h]

  v8 = a1;
  v7 = a2;
  v6 = 3;
  while ( 1 )
  {
    v2 = v7--;
    if ( !v2 )
      break;
    v3 = v8++;
    v5 = *v3;
    pending = 1;
    while ( pending )   //在后半表时先返回39再返回后半部的序号
    {
      v9[--v6] = sub_1023456(v5);    //用输入值填充v9
      if ( !v6 )
      {
        sub_1023458(v9);
        v6 = 3;
      }
    }
  }
  if ( v6 != 3 )
  {
    while ( v6 != -1 )
      v9[--v6] = 0;
    sub_1023458(v9);    //用v9填充sub_101 
  }
  return __stack_chk_guard;
}

sub_1023456是个查表函数,输入字符返回序号。不过ctable表有79个字节(明文仅限于此,其它字符不出现)每个序号0-38,这样后边一半的序号则39+i组成(两个)

__int64 __fastcall sub_1023456(int a1)   //返回输入值在ctable中的索引
{
  int v1; // ST04_4
  int i; // [rsp+0h] [rbp-Ch]
  int v4; // [rsp+4h] [rbp-8h]
  unsigned int v5; // [rsp+8h] [rbp-4h]

  v4 = a1;
  if ( sub_1023456_shifted == -1 )
  {
    if ( a1 == 126 )
      v4 = 0;
    for ( i = 0; i < 39; ++i )
    {
      if ( ctable[i] == v4 )       //前半个表
      {
        pending = 0;
        return (unsigned int)i;
      }
      if ( ctable[i + 39] == v4 )  //后半个表
      {
        pending = 1;
        sub_1023456_shifted = i;
        return 39;
      }
    }
    pending = 0;
    v5 = 37;
  }
  else
  {
    v1 = sub_1023456_shifted;
    sub_1023456_shifted = -1;
    pending = 0;
    v5 = v1;
  }
  return v5;
}

这样可以写出解码程序

a = 'F5D1,4D6B,ED6A,08A6,38DD,F7FA,609E,EBC4,E55F,E6D1,7C89,ED5B,0871,1A69,5D58,72DE,224B,3AA6,0845,7DD6,58FB,E9CC,0A2D,76B8,ED60,251A,1F6B,32CC,E78D,12FA,201A,E889,2D25,922A,4BC5,F5FF,F8E5,C79B,3A77,4BDB,EA11,5941,58BD,3A95,F5C9,A225,AD40,F8BD,095D,70B6,458C,E7A9,EA68,252F,094B,5E41,0969,6015,5ED5,F6E5,59B9,7CAF,66DF,265B,7837,57B4,7CAF,AED9,F707,6A3C,F8E5,F509,7C8B,0915,2235,336F,33E9,2D14,7C91,5804,83E5,E78D,F4EA,0874,ED6B,4B35,E839,57B4,E77C,EA68,2525,AD41,ED6F,3A4A,4BCC,6015,F440,0858,3AA6,7809,671D,0874,EA77,63AF,2E91,5845,F6C4,086D,7795,3939,57B4,7C89,82DC,32ED,B994,C7AF,9135,0E65,1B66,ED5B,3235,6577,5A80,3AD3,E776,1EE5,AD41,ED59,864C,70B4,3876,ED67,64D6,F8E5,F505,EAD9,7C9C,32ED,B994,B4EF,0C6C,F665,F5F5,9047,521A,E99E,EA68,252F,9D09,76B7,E776,1ED0,095D,0D4D,5D5A,087B,2005,1526,7E76,85AD,78B9,E8B6,782C,251C,32ED,7F68,EBE3,EA41,57FD,ED59,846D,7A05,B994,BB78,ED6A,08A6,38DD,3B5D,7E45,E839,738C,E9CC,0A2D,764A,609E,E8B6,EA68,2524,E6BB,7C9C,639F,3A95,0895,F40F,8328,EA69,7EE5,F8BD,7F7D,0D6D,70B6,458C,E8B6,EA68,251C,6065,B35F,C789,5845,7F7D,6D89,4C6E,A20E,60B5,7E45,ED59,F707,69EF,922A,4BC5,F6EF,8635,F4B9,57B4,7CF8,ED60,2510,095D,20AF,3545,F40F,8328,EA41,58A4,225D,7E7C,4BDB,F8BD,082C,EAE7,5D57,5D50,0914,E7C7,8624,7CF8,ED60,2511,7C8E,7159,8416,7EF9,E7E5,774A,3895,1EC9,7C90,09B9,58BD,5FF5,E99E,EA68,250A,224C,EA3D,73F5,7C89,53A6,3190,3B5D,1526,7DD5,666A,0919,225F,CDEF,79E1,7E7B,7E6B,082C,A277,E885,E8BB,E775,5FF7,EA68,251B,7FDF,589D,7A05,779A,8A5A,7C91,5D5C,32ED,F628,2195,F49A,0C77,EAE1,59B9,58BD,E570,E99E,EA3D,73F9,13AD,2BF5,225D,7F7D,70B6,4A9C,337A,1EC9,4D05,7E75,2578,ED59,38E5,1ECA,A210,3B5D,779A,8A6F,C790,2518,4B41,7C89,5D49,4D05,152D,73C5,79F9,4BED,913C,37C9,5D4D,53C8,0941,7C97,5D5B,346A,82D8,5F36,801F,C800'
ctable = bytes.fromhex('006162636465666768696A6B6C6D6E6F707172737475767778797A30313233343536373839200A004142434445464748494A4B4C4D4E4F505152535455565758595A282140232C2E3F2F2A293C3E00')
#每一组表示3位40进制数
a = a.split(',')
a = [int(i,16) for i in a]
t1 = []
for i in a:
    t1+=[i//1600,i//40%40,i%40]

#如第1位为39则使用表+39,其它用前39
flag = ''
shift = 0
for i in t1:
    if shift == 1:
        shift = 0
        flag += chr(ctable[i+39])  #不是40
    else:
        if i == 39:
            shift = 1
        else:
            flag += chr(ctable[i])

print(flag)

然后解出明文

'''
Milos Raonic (born 1990) is a Canadian professional tennis player. He reached a
career high world No. 4 singles ranking in May 2015, as ranked by the Associatio
n of Tennis Professionals (ATP). His career highlights include a Grand Slam fina
l at the 2016 Wimbledon Championships and two Grand Slam semifinals at the 2014
Wimbledon Championships and 2016 Australian Open. He was the 2011 ATP Newcomer o
f the Year, and has been ranked continuously inside the top 20 since August 2012
. Raonic is the first player born in the 1990s to win an ATP title, to be ranked
 in the top 10, and to qualify for the ATP World Tour Finals. He has eight ATP s
ingles titles, all won on hard courts. He is frequently described as having one
of the best serves among his contemporaries. Statistically, he is among the stro
ngest servers in the Open Era, winning 91p of service games to rank third all ti
me. Aided by his serve, he plays an all court style with an emphasis on short po
ints.
'''

网上搜到说是把明文md5后再提交,不过网上的md5也不对。最后搜来的flag才对

#1,明文md5后是flag 未提示 提交成功的值:2c8cd31daeba8753815851f13e6370b3
#2,明文md5后也不是flag  运行结果:dc5a07c9efe4722933b71455ebc74889

标签: pcb传感器进口201a75

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台