当前位置: 代码迷 >> 综合 >> pwnable.kr blackjack
  详细解决方案

pwnable.kr blackjack

热度:62   发布时间:2023-12-17 11:11:18.0

看一下题目
在这里插入图片描述
题目给出了一个连接,我们去看看

https://cboard.cprogramming.com/c-programming/114023-simple-blackjack-program.html

代码太长就不贴出来了,复制到vs编译玩一下
在这里插入图片描述
在这里插入图片描述
玩了一下发现和21点游戏规则是一样的,blackjack翻译过来也就是21点

每次,让游戏中下注,然后和电脑比赛,下注的金额不能超过所持有的金额。

题目的要求是要赢够电脑100w,这样单纯的玩肯定是不行的(赌神除外)
我们来看看有什么投机取巧的地方
在编译程序时候其实是要在编译器中选择
在这里插入图片描述说明程序使用了大量不安全的函数,如果这个程序保护没有开的话是可以执行代码的

在这里插入图片描述
scanf使用了栈地址,说明是有栈溢出的可能的
但应该不用这么麻烦,我们先来检查一下程序的逻辑有没有为什么问题,能让我们快速赢到100w,先看一下发牌的代码

int clubcard() //Displays Club Card Image
{srand((unsigned)time(NULL)); //Generates random seed for rand() functionk = rand() % 13 + 1;if (k <= 9) //If random number is 9 or less, print card with that number{//Club Cardprintf("-------\n");printf("|%c    |\n", club);printf("|  %d  |\n", k);printf("|    %c|\n", club);printf("-------\n");}...}

这里每次发牌取点数是这样的,取了时间种子生成了一个随机数,虽然看起来很随机,其实这还是一种伪随机,可以破的,但是这样破还是不够方便,再来看一下筹码的代码
在这里插入图片描述
cash_test();一开始会给我们500筹码,如果筹码归零了,会提示我们重新玩过,betting();是检查我们用户下注是否正确,可以看一下是怎么实现的

int betting() //Asks user amount to bet
{printf("\n\nEnter Bet: $");scanf("%d", &bet);if (bet > cash) //If player tries to bet more money than player has{printf("\nYou cannot bet more money than you have.");printf("\nEnter Bet: ");scanf("%d", &bet);return bet;}else return bet;
} // End Function

只检查了下注的金额是否大于已经拥有的金额,这样其实检查有点不足,如果我输入的是一个负数呢,来试试
在这里插入图片描述
疯狂跟牌,然后就输了
在这里插入图片描述
但是我们的钱却神奇的变为了501
在这里插入图片描述
我们来调试一波看一下当时的内存状态
在这里插入图片描述
由于我们输入的值是-1,所以显示是0xffffffff,而int是有符号类型的对比,所以我们这个检查是通过的,而且还发现一个问题,就是如果输入第一次的金额大于自己拥有的金额,然后会被要求输入第二次,而这个第二次输入直接就没有检查了,也就是可以输入比自己所实际拥有的金币大得多的数字来白嫖电脑,真是为所欲为啊
而如果我们输了,就会到这里计算cash

在这里插入图片描述
因为这俩个值都是int型计算负负得正,我们的钱就+1$了

然后我们直接输入-1000000,就可以变成百万负翁了XD
在这里插入图片描述
获得flag
由于我这几天都连不上pwnable.kr的服务器,所以就没有做最后的演示了,真是蛋疼