2018.7.27学习笔记

二进制逆向题目解析

1.给你个礼物你能收到吗
打开程序你会发现,它让你输入提取码:
这里写图片描述
你可以随便输入几个字符,会出现:
这里写图片描述
如果一直输入错无的话,它就会陷入一个循环:
这里写图片描述
所以,先用ida打开,用Shift+12调出字符串表,你会发现字符串表没有汉语,而程序出来的提示是汉语,所以我们无法在字符串表中找到我们想要的字符串,那么我们只能从在左侧的函数列表里查看main函数,直接进入主函数:
这里写图片描述
点开main函数,可以进入一个主函数,

int __cdecl main(int argc, const char **argv, const char **envp)
{
  _main();
  present();
  heart();
  system("pause");
  return 0;
}

然后你会发现有一个present(),这应该是我们获得礼物的函数入口,你点进去,会看到另外一串代码:

void __cdecl present()
{
  __int64 v0; // rax
  std::ostream *v1; // rax
  unsigned int x; // [rsp+24h] [rbp-5Ch]
  int xa; // [rsp+24h] [rbp-5Ch]
  int xb; // [rsp+24h] [rbp-5Ch]
  int xc; // [rsp+24h] [rbp-5Ch]
  int xd; // [rsp+24h] [rbp-5Ch]
  int xe; // [rsp+24h] [rbp-5Ch]
  int xf; // [rsp+24h] [rbp-5Ch]
  int n; // [rsp+28h] [rbp-58h]
  int y; // [rsp+2Ch] [rbp-54h]

  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, asc_47F000);
  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, &byte_47F050);
  x = 0;
  y = 2027091370;
  std::istream::operator>>(&std::cin, &n);
  while ( n != y )
  {
    if ( n == 5201314 )
    {
      std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, &byte_47F068);
      system("pause");
      exit(0);
    }
    if ( !(y % 40) )
      y = 2027091370;
    v0 = std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, &byte_47F0A0);
    v1 = (std::ostream *)std::ostream::operator<<(v0, x);
    std::operator<<<std::char_traits<char>>(v1, &byte_47F0C3);
    std::istream::operator>>(&std::cin, &n);
    ++x;
    y += 7;
  }
  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, &byte_47F0D8);
  for ( xa = 0; xa <= 78; ++xa )
  {
    std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "[");
    if ( xa <= 19 )
      Sleep(0xC8u);
    if ( xa > 74 )
      Sleep(0x3E8u);
  }
  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, asc_47F0F8);
  std::istream::operator>>(&std::cin, &n);
  if ( n != 1 )
    exit(0);
  std::operator<<<std::char_traits<char>>(
    (std::ostream *)&std::cout,
    "                                |\\          /|                                \n");
  std::operator<<<std::char_traits<char>>(
    (std::ostream *)&std::cout,
    "                                | \\________/ |                                \n");
  std::operator<<<std::char_traits<char>>(
    (std::ostream *)&std::cout,
    "                                 \\/|______|\\/                                 \n");
  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "|");
  for ( xb = 0; xb <= 38; ++xb )
    std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "—");
  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "|\n|");
  for ( xc = 0; xc <= 77; ++xc )
    std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "-");
  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "|\n|");
  for ( xd = 0; xd <= 38; ++xd )
    std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "—");
  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "|\n");
  for ( n = 0; n <= 4; ++n )
  {
    std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "   |");
    for ( xe = 0; xe <= 71; ++xe )
      std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, " ");
    std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "|   \n");
  }
  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "   ");
  for ( xf = 0; xf <= 73; ++xf )
    std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, "@");
  std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, asc_47F248);
  std::istream::operator>>((std::istream *)&std::cin);
  if ( xf != 1 )
    exit(0);
}

根据刚开始进入程序是的分析,代码里应该是有一个循环,如果我们输入错误,会执行这个循环,那么,我们要做到就是跳出这个循环,我们观察代码,找到这个循环:

while ( n != y )
  {
    if ( n == 5201314 )
    {
      std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, &byte_47F068);
      system("pause");
      exit(0);
    }
    if ( !(y % 40) )
      y = 2027091370;
    v0 = std::operator<<<std::char_traits<char>>((std::ostream *)&std::cout, &byte_47F0A0);
    v1 = (std::ostream *)std::ostream::operator<<(v0, x);
    std::operator<<<std::char_traits<char>>(v1, &byte_47F0C3);
    std::istream::operator>>(&std::cin, &n);
    ++x;
    y += 7;
  }

我们在循环里寻找跳出循环的语句,找到了 exit(0); ,找到之后,看看怎么获得,如果n=5201314,可以执行exit(0);, 所以,我们输入5201314,看一看,发现,没有得到礼物:
这里写图片描述
还是错误,当年任意键继续时,会发现它退出了程序,所以,我们可知这里的exit(0);是退出程序的,并不能退出循环,所以,我们不能寻找到跳出循环的语句,那么为了不执行这个循环,我们只能使循环条件不成立,所以,使n=y,即n= 2027091370,我们输入 2027091370;
这里写图片描述
会发现,我们得到了礼物,但是,如果我们已经输入错一次,在输入2027091370,那就还是错的:
这里写图片描述
那么这是为什么呢?我们看,while循环的最后一句:y+=7 这句是说每执行执行一次循环,y的值就会加7,所以,如果你已经输入错了一次,要想输入正确提取码,是while循环不成立,就要在 2027091370后面加7,正确的前面错了几次,就要加上几个七:
这里写图片描述
这里写图片描述
链接:C语言中Exit函数的使用
2.pyc文件
这里写图片描述
网上百度一个python反编译在线工具,反编译上述pyc文件,得到一串代码:

#!/usr/bin/env python
# visit http://tool.lu/pyc/ for more information
import base64

def encode(message):
    s = ''
    for i in message:
        x = ord(i) ^ 32
        x = x + 16
        s += chr(x)

    return base64.b64encode(s)

correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
    print 'correct'
else:
    print 'wrong'

我们从下往上推:

correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
    print 'correct'
else:
    print 'wrong'

我们可知,flag是字符,输入flag,如果经过 encode()函数得到的结果是correct,则输出的是correct,否则,错误,我们已经知道correct= ‘XlNkVmtUI1MgXWBZXCFeKY+AaXNt’和encode()函数,反推得到flag即可,我们来看一下encode()函数:

def encode(message):
    s = ''
    for i in message:
        x = ord(i) ^ 32
        x = x + 16
        s += chr(x)

    return base64.b64encode(s)

从后面得知,encode(flag)=correct,那么根据上面的函数可知,message就是flag,则最后输出的correct就是函数里最后得return返回的值,我们反推回去,base64.b64encode(s),这句是指把s进行base64进行加密,所以我们应该先把correct解密回去,所以我们可以写Python脚本:

import base64
correct='XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
s=base64.b64decode(correct)

然后求flag,根据encode函数可知,知道s后应该求x,x是s中每一个字符的ASCII值,然后用ord()函数求x,x减去十六后在复制给x,再往上一步是x是flag中的每一个值得ASCII值与32异或,所以flag中的字符就是x与32异或所得的数在ASCII表中对应的字符,所以,我们可以写python脚本:

flag=''
for i in range(0,len(s)):
    x = ord(s[i])
    x = x-16
    flag +=chr(x^32)

所以,我们就可以写出脚本,运行得到flag:

import base64
correct='XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
s=base64.b64decode(correct)
flag=''
for i in range(0,len(s)):
    x = ord(s[i])
    x = x-16
    flag +=chr(x^32)
print flag

输出的结果:

nctf{d3c0mpil1n9_PyC}

链接:python中base64模块的加解密函数
链接:Python chr() 函数
链接:Python ord() 函数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值