二进制

2018.7.24

兴趣是最好的老师
首先打开程序,发现打不开程序,我们可以先把他拖进Editor中看看是不是文件中哪里出错了,拖进后出现
这里写图片描述
但是我们知道
第一个字段e_magic被定义成字符“MZ”作为识别标志,后面的一些字段指明了入口地址、堆栈位置和重定位表位置等。
对于PE文件来说,有用的是最后的e_lfanew字段(文件的偏移0x3C(第60字节)处是是一个4字节的PE文件签名的偏移地址),这个字段指出了真正的PE文件头在文件中的位置。
从图中我们可以看到e_lfanew的值为000000E8,也就是说000000E8处是我们的PE文件头的位置。
但我们从上图中可以看到000000E8处并不是PE文件头而是00,这就发现了错误,我们应该把它改为PE文件头,如下图
这里写图片描述
改完之后,我们再打开程序,就可以运行了,这时程序框中出现please enter flag:,
我们就知道要求出flag,我们可以把文件拖进IDA32位后,找到伪代码,接下来分析代码

__int64 main_0()
{
  int v0; // edx
  __int64 v1; // ST00_8
  int v3; // [esp+0h] [ebp-1A0h]
  const char **v4; // [esp+4h] [ebp-19Ch]
  const char **v5; // [esp+8h] [ebp-198h]
  int v6; // [esp+Ch] [ebp-194h]
  int i; // [esp+D4h] [ebp-CCh]
  int v8; // [esp+E0h] [ebp-C0h]
  int v9; // [esp+ECh] [ebp-B4h]
  int v10; // [esp+F0h] [ebp-B0h]
  int v11; // [esp+F4h] [ebp-ACh]
  int v12; // [esp+F8h] [ebp-A8h]
  int v13; // [esp+FCh] [ebp-A4h]
  int v14; // [esp+100h] [ebp-A0h]
  int v15; // [esp+104h] [ebp-9Ch]
  int v16; // [esp+108h] [ebp-98h]
  int v17; // [esp+10Ch] [ebp-94h]
  int v18; // [esp+110h] [ebp-90h]
  int v19; // [esp+114h] [ebp-8Ch]
  int v20; // [esp+118h] [ebp-88h]
  int v21; // [esp+11Ch] [ebp-84h]
  int v22; // [esp+120h] [ebp-80h]
  int v23; // [esp+124h] [ebp-7Ch]
  int v24; // [esp+128h] [ebp-78h]
  int v25; // [esp+12Ch] [ebp-74h]
  int v26; // [esp+130h] [ebp-70h]
  int v27; // [esp+134h] [ebp-6Ch]
  int v28; // [esp+138h] [ebp-68h]
  int v29; // [esp+13Ch] [ebp-64h]
  int v30; // [esp+140h] [ebp-60h]
  char v31; // [esp+14Fh] [ebp-51h]
  char v32[17]; // [esp+178h] [ebp-28h]
  char v33; // [esp+189h] [ebp-17h]
  char v34; // [esp+18Ah] [ebp-16h]
  char v35; // [esp+18Bh] [ebp-15h]
  char v36; // [esp+18Ch] [ebp-14h]
  char v37; // [esp+18Dh] [ebp-13h]

  v31 = 0;
  v9 = 1;
  v10 = 4;
  v11 = 14;
  v12 = 10;
  v13 = 5;
  v14 = 36;
  v15 = 23;
  v16 = 42;
  v17 = 13;
  v18 = 19;
  v19 = 28;
  v20 = 13;
  v21 = 27;
  v22 = 39;
  v23 = 48;
  v24 = 41;
  v25 = 42;
  v26 = 26;
  v27 = 20;
  v28 = 59;
  v29 = 4;
  v30 = 0;
  printf("please enter flag:");
  while ( 1 )
  {
    v6 = getch();
    v32[v31] = v6;
    if ( !(_BYTE)v6 || v32[v31] == 13 )
      break;
    if ( v32[v31] == 8 )
    {
      printf("\b\b");
      --v31;
    }
    else
    {
      printf("%c", v32[v31++]);
    }
  }
  v8 = 0;
  for ( i = 0; i < 17; ++i )
  {
    if ( v32[i] != byte_415768[*(&v9 + i)] )
      v8 = 1;
  }
  if ( v33 != 49 || v34 != 48 || v35 != 50 || v36 != 52 || v37 != 125 )
    v8 = 1;
  v32[v31] = 0;
  printf("\r\n");
  if ( v8 )
  {
    printf("wrong\n");
    main(v3, v4, v5);
  }
  else
  {
    printf("success\n");
  }
  system("pause");
  HIDWORD(v1) = v0;
  LODWORD(v1) = 0;
  return v1;
}

我们肯定是要它输出success的,所以if条件就要不成立,v8就要等于0,再往上分析

for ( i = 0; i < 17; ++i )
  {
    if ( v32[i] != byte_415768[*(&v9 + i)] )
      v8 = 1;
  }
  if ( v33 != 49 || v34 != 48 || v35 != 50 || v36 != 52 || v37 != 125 )
    v8 = 1;

我们就要让for循环中的if条件一直不成立,和下面的if条件也不成立。*(&v9 + i)相当于是以&v9为首地址的数组,我们可以通过代码开头定义v9后的地址知道,v9到v30的地址是连续的,所以v9到v30可以当成一个数组。
接下来我们点开byte_415768发现
这里写图片描述
我们可以按R将73h转换成字符’s’,这时我们就可以得到byte_415768中的字符了,为’sKfxEeft}f{gyrYgthtyhifsjei53UUrrr_t2cdsef66246087138\0087138’

 v6 = getch();
    v32[v31] = v6;

我们通过上面的代码得到v32就是我们要求的flag,所以我们可以写脚本,如下

a='sKfxEeft}f{gyrYgthtyhifsjei53UUrrr_t2cdsef66246087138\0087138'
b=[1,4,14,10,5,36,23,42,13,19,28,13,27,39,48,41,42,26,20,59,4,0]
for i in range(17):
    print(a[b[i]],end='')

因为我们还要让 v33 != 49 || v34 != 48 || v35 != 50 || v36 != 52 || v37 != 125 不成立,所以要让
v33 == 49 && v34 == 48 && v35 == 50 && v36 ==52 && v37 == 125 ,又因为定义中它们都是字符,所以可以按R键让49,48,50,52,125转换成字符,又因为v32[17]到v37地址也是连续的,所以v33、v34、v35、v36、v37改变v32字符串也会改变,所以最终脚本输出应加上

print('1024}')

文件改动(reverseme)
将文件用editor打开后,出现如下格式
这里写图片描述
这里写图片描述
可以看到文件开头为D9FF,结尾为D8FF,因为JPEG图片以“FF D8”开头,以“FF D9”结尾,所以可以想到这个文件可能是被倒序了,我们现在要让它恢复原来的格式,才能得到图片。我们可以以二进制格式读取这个文件,然后再让这个文件以二进制格式倒序写入另一个文件,另一个文件就是我们要得到的格式。脚本如下:

myfile=open("reverseMe","rb")
file=myfile.read()

newfile=open("Me.jpg","wb")
newfile.write(file[::-1])

open (文件名[,访问模式])
rb:以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
wb:以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
fileObject.write(string) 在这里,被传递的参数是要写入到已打开文件的内容。
a = [0,1,2,3,4,5,6,7,8,9]
b = a[i:j] 表示复制a[i]到a[j-1],以生成新的list对象
b = a[1:3] 那么,b的内容是 [1,2]
当i缺省时,默认为0,即 a[:3]相当于 a[0:3]
当j缺省时,默认为len(alist), 即a[1:]相当于a[1:10]
当i,j都缺省时,a[:]就相当于完整复制一份a了
b = a[i:j:s]这种格式呢,i,j与上面的一样,但s表示步进,缺省为1.
所以a[i:j:1]相当于a[i:j]
当s<0时,i缺省时,默认为-1. j缺省时,默认为-len(a)-1
所以a[::-1]相当于 a[-1:-len(a)-1:-1],也就是从最后一个元素到第一个元素复制一遍。所以你看到一个倒序的东西。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值