XCTF-攻防世界CTF平台-Reverse逆向类——31、hackme

先用ExeinfoPE查壳查看文件信息:
在这里插入图片描述

是Linux ELF 64位文件,没有加壳
然后用IDA64打开文件,打开字符串窗口:
在这里插入图片描述

可以看到“Give me the password:”、“Congras\n”、“Oh no!\n”字符串,可能是程序输出的字符串,双击 “Give me the password:”找到它在数据段中存储的位置:
在这里插入图片描述

选中aGiveMeThePassw按X快捷键,找到使用该变量的地方:
在这里插入图片描述

跳转到函数中使用aGiveMeThePassw变量的地方:
在这里插入图片描述

尝试按F5反编译代码:
在这里插入图片描述

我们也可以先找到Linux ELF文件的start函数,程序启动都是从它开始的,它负责初始化一些环境变量之类的参数,然后调用main函数,main函数结束之后又会返回start函数:
在这里插入图片描述

其中sub_400F8E函数便是main函数所在的位置,其他函数都是main函数之前的初始化以及main函数之后的清除。
sub_400F8E函数中:
在这里插入图片描述

sub_407470((__int64)"Give me the password: ", a2);
sub_4075A0((__int64)"%s", v3);

sub_407470函数很像printf函数输出提示语句“Give me the password: ”,sub_4075A0函数则很像scanf函数获取我们的输入,注意的是sub_4075A0函数在我的IDA中刚开始F5反编译识别出来是:

sub_4075A0((__int64)"%s");

点进sub_4075A0函数查看之后返回又变成了

sub_4075A0((__int64)"%s", v3);

这里应该是IDA的反编译识别参数出了问题,也是IDA的F5反编译功能的弊端,它能给我们提供方便,但有时候也会给我们带来困扰误导我们。
查看源汇编代码:
在这里插入图片描述

可以看到sub_407470函数和sub_4075A0函数,都有edi和rsi两个参数。
再回到源代码的分析:
在这里插入图片描述

所以程序的逻辑就是:
1、输入的字符串保存在v3[136],长度i为22时就给BOOL变量v13赋值1,否则为0;(也就是说输入字符串的长度必须为22,否则下面v13的值就会为0输出“Oh no!”);
2、之后由v12从10递减到0控制10次循环,10次循环中每次v9通过sub_406D90()函数 % 22获得一个22以内的数,作为输入的字符数组和指定的字节数组byte_6B4270的下标;
3、然后由v10从0递增到v9+1控制v9次循环,v9次循环次循环中v11 = 1828812941 * v11 + 12345,经过v9次循环之后得到一个v11的值;
4、判断如果v8(字节数组byte_6B4270中下标v9的值)不等于v11异或v7(输入字符数组的值中下标v9的值),就会把v13的值变为0;
5、最后判断v13的值如果为1就输出"Congras\n",如果为0就输出"Oh no!\n"。
其中sub_406D90()函数是一个随机数发生器,随机产生一个伪随机数,sub_406D90() % 22得到的就是一个22以内的数,作为输入的字符数组和指定的字节数组byte_6B4270的下标。
也就是我们要输入一个长度为22的字符串,然后程序有10次循环,每次生成一个随机下标,从指定字节数组byte_6B4270中取出随机下标的字节v8,从输入的字符数组中取出随机下标的字符v7,以及经过随机下标次递归的v11,要求每次v8等于v7异或v11,就能通过判断输出"Congras\n"。
所以我们要得到输入的字符串,只需要循环22次从0到21,每次把byte_6B4270[i]和每次计算得到的v11异或即可得到对应的输入的字符。
其中byte_6B4270[]的值:
在这里插入图片描述

直接在IDA中编写idc脚本,可以直接使用byte_6B4270[]的值
源代码flag.idc:

auto i;
auto v11 = 0;
auto v7;
for(i = 0;i < 22; ++i){
v11 = 1828812941 * v11 + 12345;
v7 = v11 ^ Byte(0x6B4270 + i);
Message("%s",v7);
}

运行截图:
在这里插入图片描述

得到falg是flag{d826e6926098ef46}
把byte_6B4270[]的值dump出来,C语言写的代码
flag.c:

#include<stdio.h>

int main()
{
    int byte_6B4270[] ={
    0x5F, 0xF2, 0x5E, 0x8B, 0x4E, 0x0E, 0xA3, 0xAA, 0xC7, 0x93,
    0x81, 0x3D, 0x5F, 0x74, 0xA3, 0x09, 0x91, 0x2B, 0x49, 0x28,
    0x93, 0x67, 0x00, 0x00
    };
    //输入的字符串
    int v7 = 0;
    int v11 = 0;
    int i;
	for(i=0;i<22;i++)
	{
        v11 = v11 * 1828812941 + 12345;
		v7 = byte_6B4270[i] ^ v11;
		printf("%c",v7);
	}
    return 0;
}

运行截图:
在这里插入图片描述

得到falg是flag{d826e6926098ef46}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值