2018.7.26学习笔记

二进制逆向题目解析

where are your flag
我们先用ida打开这个文件,我们把文件拖进ida(ida有64位和32位的,我们要先确定文件用哪一个),打开文件后,出现的是汇编代码为流程图浏览模式,
流程图浏览模式
使用Shift+12调出字符串表,再根据这些字符串,查看引用的地方,
这里写图片描述
我们找到我们想要找到的字符串,点进去:仔细观察这些字符串,我们会发现有一串字符串是“where are you flag”,这就是我们要的结果,点进去:
这里写图片描述
在上图中我们可以看到我们点进去的有我们要的“where are you flag”,在后面的箭头处点击,出来代码流程图:
这里写图片描述
再用F5找到反编译界面,找到代码:
这里写图片描述
其实还有一种方法,我们不论是什么语言,都有一个主函数,所以我们可以直接在左侧的函数列表里查看main函数,找到main函数,点进去,也可以找到上述界面:
这里写图片描述
进去反编译后的代码页面后,我们会看到这样一串代码:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  if ( argc <= 1 )
  {
    puts("where is your flag?");
  }
  else if ( (unsigned int)test((__int64)argv[1]) )
  {
    puts("you got it!");
  }
  else
  {
    puts("try again!");
  }
  return 0;
}

对于这串代码,我们可以分析一下:
如果 (unsigned int)test((__int64)argv[1]),则输出“you got it!”你的flag正确,否则,“try again!”再试一次,是错误的,
那么test是什么呢,我们点进去看一下,会看到另一串代码:

_BOOL8 __fastcall test(__int64 a1)
{
  signed int i; // [rsp+1Ch] [rbp-24h]
  __int64 s2; // [rsp+20h] [rbp-20h]
  __int64 v4; // [rsp+28h] [rbp-18h]
  __int16 v5; // [rsp+30h] [rbp-10h]
  char v6; // [rsp+32h] [rbp-Eh]
  unsigned __int64 v7; // [rsp+38h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  s2 = 4118914718243424768LL;
  v4 = 4112445312588908291LL;
  v5 = 5391;
  v6 = 27;
  if ( strlen((const char *)a1) != 19 )
    return 0LL;
  for ( i = 0; i <= 18; ++i )
    *((_BYTE *)&s2 + i) ^= 0x66u;
  return !memcmp((const void *)a1, &s2, 5uLL)
      && *(_BYTE *)(a1 + 18) == v6
      && *(_BYTE *)(a1 + 7) == *(_BYTE *)(a1 + 10)
      && *(_BYTE *)(a1 + 10) == *(_BYTE *)(a1 + 13)
      && *(char *)(a1 + 13) == SHIBYTE(s2) - 49
      && !memcmp((const void *)(a1 + 5), (char *)&v4 + 5, 2uLL)
      && !memcmp((const void *)(a1 + 8), &v5, 2uLL)
      && !memcmp((const void *)(a1 + 11), (char *)&s2 + 5, 2uLL)
      && !memcmp((const void *)(a1 + 14), &v4, 4uLL);
}

我们继续来分析这串代码:
代码刚开始定义了a1,即是上一串代码中的argv[1],看下面的代码可知,一直使用a1和其他比较,所以a1使我们要找的flag,我们来看这一串:

if ( strlen((const char *)a1) != 19 )
    return 0LL

如果a1的长度不等于19,返回值是0,所以a1的长度一定为十九,(LL是longlong类型的字面值常量)
链接:C语言strlen()函数用法
我们再往下看这串代码:

 for ( i = 0; i <= 18; ++i )
    *((_BYTE *)&s2 + i) ^= 0x66u;

这是一个循环,s2中的所有元素与0x66进行异或,得到的结果再返回给s2,我们由循环的次数得知,这个循环进行了19次,但是,我们再看s2的值,s2=4118914718243424768,右击把s2转化为十六进制数,s2=0x3929531D01070A00,我们可知s2中就只有八个元素,即:s2=[0x00,0x0a,0x07,0x01,0x1d,0x53,0x29,0x39],那么为什么循环了十九次呢?我们再看在s2下面还定义了v4,v5,v6,我们点一下查看一下地址,发现s2,v4,v5,v6地址是在一起的,
-0000000000000020
-0000000000000018
-0000000000000010
-000000000000000E
在下面又把a1和s2、v4、v5、v6放在一起比较,所以我们可知这里的十九次循环应该是把v4、v5、v6放在s2里了,,把v4、v5、v6转化为十六进制数:v4=0x391257391F150703,v5=0x150F,v6=0x1B,又由下面的代码知,a1要与s2、v4、v5、v6放在一起比较,a1是flag,所以要把s2化作字符
所以我们可以用Python写代码为:

flag=[0]*19
s2=[0x00,0x0a,0x07,0x01,0x1d,0x53,0x29,0x39,0x03,0x07,0x15,0x1f,0x39,0x57,0x12,0x39,0x0f,0x15,0x1b]

for i in range(19):
    s2[i]=chr(s2[i]^0x66)

链接:python 初始化一个定长的数组
链接:python chr()
继续向下看代码:

return !memcmp((const void *)a1, &s2, 5uLL)
      && *(_BYTE *)(a1 + 18) == v6
      && *(_BYTE *)(a1 + 7) == *(_BYTE *)(a1 + 10)
      && *(_BYTE *)(a1 + 10) == *(_BYTE *)(a1 + 13)
      && *(char *)(a1 + 13) == SHIBYTE(s2) - 49

“return !memcmp((const void *)a1, &s2, 5uLL)”的意思是:把a1的前五项与s2的前五项相比较,如果相等返回0,因为我们要让它返回1,前面又有一个“!”符号,所以我们要令a1和s2的前五项相等,写出python函数:

flag[0:5]=s2[0:5]

链接:C 库函数 - memcmp()
(_BYTE )(a1 + 18) == v6”这一句是说,a1[18]=v6,由我们在上面写的python脚本知,我们可写python:

flag[18]=s2[18]

“&& (_BYTE )(a1 + 7) == (_BYTE )(a1 + 10), && (_BYTE )(a1 + 10) == (_BYTE )(a1 + 13),&& (char )(a1 + 13) == SHIBYTE(s2) - 49”我们再来看这一串代码,它的意思是a[7]=a[10],而a[10]=a[13],那么a[13]等于s2的最后一位的ascii值减去49,然后再取这个ascii值所对应的字符,所以我们可以写python脚本:

flag[13]=chr(ord(s2[7])-49)
flag[10]=flag[13]
flag[7]=flag[10]

链接:python ord()函数
再看下面的代码:

&& !memcmp((const void *)(a1 + 5), (char *)&v4 + 5, 2uLL)
      && !memcmp((const void *)(a1 + 8), &v5, 2uLL)
      && !memcmp((const void *)(a1 + 11), (char *)&s2 + 5, 2uLL)
      && !memcmp((const void *)(a1 + 14), &v4, 4uLL);

这串代码和上面的一样,所以我们可知,a1的第6,7项和v4的第6,7项相等,a1的第9,10项和v5里的两项相等,a1的第12,13两项和s2的第6,7两项相等,而a1的第15,16,17,18四项和v4的前四项相等,所以我们写python脚本:

flag[5]=s2[8+5]
flag[6]=s2[8+5+1]
flag[8]=s2[16]
flag[9]=s2[17]
flag[11]=s2[5]
flag[12]=s2[6]
flag[14:18]=s2[8:12]

但是我们这里定义的a1(即flag)是列表,我们要把它转化为字符串:

a=""
for i in range(len(s2)):

    a+=flag[i]

所以,总结来看,我们的得到的python脚本是:

flag=[0]*19
s2=[0x00,0x0a,0x07,0x01,0x1d,0x53,0x29,0x39,0x03,0x07,0x15,0x1f,0x39,0x57,0x12,0x39,0x0f,0x15,0x1b]
for i in range(19):
    s2[i]=chr(s2[i]^0x66)
print (ord(s2[7]))
flag[0:5]=s2[0:5]
flag[18]=s2[18]
flag[13]=chr(ord(s2[7])-49)
flag[10]=flag[13]
flag[7]=flag[10]
flag[5]=s2[8+5]
flag[6]=s2[8+5+1]
flag[8]=s2[16]
flag[9]=s2[17]
flag[11]=s2[5]
flag[12]=s2[6]
flag[14:18]=s2[8:12]
a=""
for i in range(len(s2)):

    a+=flag[i]
print (a)

运行后的结果:
flag{1t.is.5O.easy}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值