## [BOJ] 1389. 케빈 베이컨의 6단계 법칙

루프 순서에 유의하자.

#include <stdio.h>

#define N_SIZE		(100)
#define N_OFFSET	(2)
#define N_MAX		(N_SIZE + N_OFFSET)

int main() {
int n, m, src, dest;
int graph[N_MAX][N_MAX];
int minIndex = 1;
bool loop = true;

scanf("%d %d", &n, &m);

for (int i = 0; i < m; i++) {
scanf("%d %d", &src, &dest);
graph[src][dest] = graph[dest][src] = 1;
}

for (int k = 1; k <= n; k++) {
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (graph[i][k] && graph[k][j]) {
if (graph[i][j] == 0 || graph[i][k] + graph[k][j] < graph[i][j])
graph[i][j] = graph[j][i] = graph[i][k] + graph[k][j];
}
}
}
}

for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
graph[i] += graph[i][j];
}

if (graph[i] < graph[minIndex]) {
minIndex = i;
}
}

printf("%d\n", minIndex);

return 0;
}



• 풀이법 : 플로이드-워셜 알고리즘
• 주의 : 플로이드-워셜 알고리즘은 k, i, j 순으로 루프를 타야되는걸 주의

## [BOJ] 15549. if

신선하고 재밌는 문제

int –2147483648

• 풀이법 : Overflow
• 참고 : Integer range –2,147,483,648 ~ 2,147,483,647

## [BOJ] 9631 The Alphabet Sticker

#include <stdio.h>

int main() {
int T;

scanf("%d", &T);

while (T--) {
char str = { 0 };
long long result = 1;
int before = 0, cnt = 0;

scanf("%s", str);

for (int i = 0; str[i]; i++) {
if (str[i] != '?') {
if(before){
if (before != str[i]) {
result *= (cnt + 1);
result %= 1000000007;
}
}
before = str[i];
cnt = 0;
}
else {
cnt++;
}
}

printf("%lld\n", result);
}

return 0;
}

## [BOJ] 1449 수리공 항승

날로먹는 문제

#include <stdio.h>

int main() {
int n, l, pos, cnt = 0;
bool pipe = { 0 };

scanf("%d %d", &n, &l);

for (int i = 0; i < n; i++) {
scanf("%d", &pos);
pipe[pos] = true;
}

for (int i = 0; i <= 1000; i++) {
if (pipe[i]) {
for (int j = 0; j < l && i + j <= 1000; j++) {
pipe[i + j] = false;
}

cnt++;
}
}

printf("%d\n", cnt);

return 0;
}

## [BOJ] 9084 동전

그냥 간단한 DP문제.
m이 먼저나왔으면 좋았을텐데, 동전을 다 받은다음 나온다.
dp 테이블 크기가 작고 귀찮아서 대충 풀었는데, 시간복잡도를 고려하면 배열을 선언해서 동전을 저장한 다음, m을 받고 난 뒤, dp테이블을 m까지 계산하는게 빠르다.

#include <stdio.h>

int main() {
int T;

scanf("%d", &T);

while (T--) {
int dp = { 1 };
int n, c, m;

scanf("%d", &n);

for (int i = 0; i < n; i++) {
scanf("%d", &c);

for (int i = 0; i <= 10000 - c; i++) {
if (dp[i]) {
dp[i + c] += dp[i];
}
}
}

scanf("%d", &m);

printf("%d\n", dp[m]);
}

return 0;
}

## [BOJ] 9634 Cup of Cowards

풀긴 풀었는데, 솔직히 테스트케이스가 부실해서 통과한거 같다.
대회에서 사용했던 I/O(http://acmacpc.org/archive/y2013/)로 테스트해보면 간당간당한게 몇 개 있다. 내 컴퓨터에서 약 2~3초 정도 걸리는데, BOJ서버에선 3초를 넘길 거 같다.

풀어도 찜찜한 이 기분. 그래서 정석 풀이법을 찾아봤다.
대회에 참가했던 사람에 의하면 이 문제의 출제 의도는 Meet in the middle로 푸는것이라 한다.(https://www.quora.com/This-algorithmic-problem-wasnt-solved-on-a-recent-ACM-ICPC-regional-contest-How-can-it-be-solved/answer/Islam-Diaa)

나의 경우엔 백트래킹으로 풀었다.
계속 타임리밋이 뜨길래 메모이제이션에 inline까지 써가면서 처절하게 풀었는데 효과가 없었다. 디버깅을 해보니 함수콜에 오버헤드가 큰 것이 원인이였다.
(inline인데 왜 오버헤드가 큰걸까… 예전에 C++배울땐 매크로함수랑 똑같은 기능이라 배운것 같은데…)

그래서 최대한 함수콜을 줄이기 위해 내림차순으로 정렬한 뒤 백트래킹을 진행했다.
이렇게하면 if (dmg + remain_dmg < hp) return;과 연계되어 함수콜이 많이 줄어든다.

나름 많이 헤맨거 같은데 모로가도 서울만 가면 된다고, 메모리 & 시간으로 1등먹어서 기분 좋다. #include <stdio.h>

long long stat = { 0 };
long long memo = { 0 };
long long T, hp;
long long  minCost, minDmg;

long long pow(long long val, int k) {
long long result = 1;

for (int i = 0; i < k; i++) {
result *= val;
}

return result;
}
inline void backtracking(int charCode, long long dmg, long long cost, long long remain_dmg) {
long long _cost, _dmg;

if (dmg + remain_dmg < hp)
return;

for (int i = 0; i <= stat[charCode]; i++) {
_cost = cost + memo[i][charCode];
_dmg = dmg + memo[i][charCode];

if (_cost > minCost)
return;

if (_dmg >= hp) {
if (minCost >= _cost) {
if (minCost != _cost || minDmg >= _dmg)
minDmg = _dmg;

minCost = _cost;
}

return;
}

if (charCode < 4) {
backtracking(charCode + 1, _dmg, _cost, remain_dmg - memo[stat[charCode]][charCode]);
}
}
}

int main() {
scanf("%lld", &T);

while (T--) {
long long maxDmg = 0, maxCost = 0;

minCost = pow(10, 12) * 5;
minDmg = pow(10, 12) * 5;

scanf("%lld", &hp);

for (int i = 0; i < 5; i++) {
scanf("%lld %lld %lld", &stat[i], &stat[i], &stat[i]);
maxDmg += stat[i] * stat[i];
maxCost += stat[i] * stat[i];
}

if (maxDmg <= hp) {
if (maxDmg == hp) {
printf("%lld %lld\n", maxCost, maxDmg);
}
else {
printf("We are doomed!!\n");
}
}
else {
for (int i = 0; i < 4; i++) {
for (int j = i + 1; j < 5; j++) {
if (stat[i]  < stat[j]) {
stat[i] ^= stat[j] ^= stat[i] ^= stat[j];
stat[i] ^= stat[j] ^= stat[i] ^= stat[j];
stat[i] ^= stat[j] ^= stat[i] ^= stat[j];
}
}
}

for (int i = 0; i < 5; i++) {
for (int j = 0; j <= stat[i]; j++) {
memo[j][i] = stat[i] * j;
memo[j][i] = stat[i] * j;
}
}
backtracking(0, 0, 0, maxDmg);
printf("%lld %lld\n", minCost, minDmg);
}
}

}

## [BOJ] 7286 Ancient Keyboard

이건 솔직히 영어 지문 해석 문제다.

#include <stdio.h>

int main() {
int T;
int n;

scanf("%d", &T);

while (T--) {
int timeline = { 0 };
int a, b, max = 0;

scanf("%d", &n);

for (int i = 0; i < n; i++) {
scanf("\n%*c %d %d", &a, &b);
max = max > b ? max : b;

for (; a < b; a++)
timeline[a]++;
}

for (int i = 0; i < max; i++)
timeline[i] > 0 ? printf("%c", 'A' + timeline[i] - 1) : NULL;

printf("\n");
}

return 0;
}

## [pwnable] uaf

Mommy, what is Use After Free bug?

UAF(Use After Free)에 관한 문제이다.

코드를 까보자

#include <fcntl.h>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
using namespace std;

class Human{
private:
virtual void give_shell(){
system("/bin/sh");
}
protected:
int age;
string name;
public:
virtual void introduce(){
cout << "My name is " << name << endl;
cout << "I am " << age << " years old" << endl;
}
};

class Man: public Human{
public:
Man(string name, int age){
this->name = name;
this->age = age;
}
virtual void introduce(){
Human::introduce();
cout << "I am a nice guy!" << endl;
}
};

class Woman: public Human{
public:
Woman(string name, int age){
this->name = name;
this->age = age;
}
virtual void introduce(){
Human::introduce();
cout << "I am a cute girl!" << endl;
}
};

int main(int argc, char* argv[]){
Human* m = new Man("Jack", 25);
Human* w = new Woman("Jill", 21);

size_t len;
char* data;
unsigned int op;
while(1){
cout << "1. use\n2. after\n3. free\n";
cin >> op;

switch(op){
case 1:
m->introduce();
w->introduce();
break;
case 2:
len = atoi(argv);
data = new char[len];
cout << "your data is allocated" << endl;
break;
case 3:
delete m;
delete w;
break;
default:
break;
}
}

return 0;
}

virtual void give_shell(){
system("/bin/sh");
}

딱봐도 이 부분을 실행시켜야 할 것 같다.

그런데 코드에 저 부분을 부르는 곳이 없다.

뭔가 다른방법을 사용해야 할 것 같은데,

cout << "1. use\n2. after\n3. free\n";
cin >> op;

switch(op){
case 1:
m->introduce();
w->introduce();
break;
case 2:
len = atoi(argv);
data = new char[len];
cout << "your data is allocated" << endl;
break;
case 3:
delete m;
delete w;
break;
default:
break;
}

메인함수에 use after free라고 대놓고 UAF를 써달라는 부분이 있다.

그럼 이제 UAF가 뭔지 알아보자.

UAF는 말 그대로 할당한 메모리 영역을 free한 다음 재사용할 때를 말한다.

case 3:
delete m;
delete w;
break;

즉 여기서 m과 w를 해제하고,

case 1:
m->introduce();
w->introduce();
break;

여기서 다시 사용하는게 UAF다.

보통의 경우 런타임 에러가 발생하겠지만, 모종의 방법으로 m과 w가 있었던 곳을 조작하면 개발자가 의도치 않은 기능을 수행할 수 있다.

size_t len;
char* data;
unsigned int op;
while(1){
cout << "1. use\n2. after\n3. free\n";
cin >> op;

switch(op){
case 1:
m->introduce();
w->introduce();
break;
case 2:
len = atoi(argv);
data = new char[len];
cout << "your data is allocated" << endl;
break;
case 3:
delete m;
delete w;
break;
default:
break;
}
}

이걸 peda로 까보자

breakpoint는 main+265에 걸고 수행시켜본다. RBX를 보면 0xbb6ca0 –> 0x401550 –> 0x40117a (<ZN5Human10give_shellEv>: push rbp)라는 부분이 보인다.

0x40117a를 실행 시킬 수 있다면 쉘을 딸 수 있을 것 같다.

계속해서 0x401550를 참조해보자

x/32x 0x401550과 x/32 *0x401550을 쳐보자 먼저 아래쪽을 보면(x/32x *0x401550)

give_shell의 주소는 0x40117a

introduce의 주소는 0x401192이다. (0x40119a-0x8)

다시 위쪽을 보면 0x401590에 0x40117a(give_shell)과 0x401192(introduce)가 나란히 위치한걸 볼 수 있다.

이제 페이로드를 작성해 case2를 통해 주소를 조작하여, introduce대신 give_shell을 실행하도록 하면 된다.

breakpoint 는 main+316이다.

우선 payload를 작성하기전에 파일이 메모리에 어떻게 들어가는지 알 필요가 있다.

파일을 하나 만들고, AAAABBBBCCCCDDDD라고 쓴 후에 저장한다.

그리고 peda로 들어가서 run 16 [filename]으로 실행한다.

먼저 3을 입력해 기존의 할당된 m, w를 해제시켜준다.

그 다음 2를 입력해 페이로드를 넣어본다.

main+419

그 다음 case 2로 들어가 할당을 해주고 값을 초기화 하는데, 적절한 방법을 통해 Human* -> introduce();를 Human -> give_shell();로 바꿔주면 클리어.

uaf@ubuntu:/tmp/uaf$python ex.py [+] Starting local process '/home/uaf/uaf': Done [*] Switching to interactive mode 1. use 2. after 3. free your data is allocated 1. use 2. after 3. free your data is allocated 1. use 2. after 3. free$ cat ~/flag
yay_f1ag_af*********

## [pwnable] lotto

Mommy! I made a lotto program for my homework.
do you want to play?

코드부터 까보자.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

unsigned char submit;

void play(){

int i;
printf("Submit your 6 lotto bytes : ");
fflush(stdout);

int r;

printf("Lotto Start!\n");
//sleep(1);

// generate lotto numbers
int fd = open("/dev/urandom", O_RDONLY);
if(fd==-1){
exit(-1);
}
unsigned char lotto;
exit(-1);
}
for(i=0; i<6; i++){
lotto[i] = (lotto[i] % 45) + 1;		// 1 ~ 45
}
close(fd);

// calculate lotto score
int match = 0, j = 0;
for(i=0; i<6; i++){
for(j=0; j<6; j++){
if(lotto[i] == submit[j]){
match++;
}
}
}

// win!
if(match == 6){
system("/bin/cat flag");
}
else{
}

}

void help(){
printf("- nLotto Rule -\n");
printf("nlotto is consisted with 6 random natural numbers less than 46\n");
printf("your goal is to match lotto numbers as many as you can\n");
printf("if you win lottery for *1st place*, you will get reward\n");
printf("mathematical chance to win this game is known to be 1/8145060.\n");
}

int main(int argc, char* argv[]){

while(1){

printf("1. Play Lotto\n");
printf("2. Help\n");
printf("3. Exit\n");

case 1:
play();
break;
case 2:
help();
break;
case 3:
printf("bye\n");
return 0;
default:
break;
}
}
return 0;
}

2점짜리라 그런지 문제가 굉장히 쉽다.

	// calculate lotto score
int match = 0, j = 0;
for(i=0; i<6; i++){
for(j=0; j<6; j++){
if(lotto[i] == submit[j]){
match++;
}
}
}

// win!
if(match == 6){
system("/bin/cat flag");
}
else{
}

play()안의 정답 판정을 하는 부분의 알고리즘이 잘못되었다.

이렇게 코드를 짜면 중복체크가 되어버린다.

예를들면 당첨번호가 1, 2, 3, 4, 5, 6이고 내가 입력한게 1, 1, 1, 1, 1, 1이면 match가 6으로  정답이 되어버린다.

그럼 남은건 하나로 찍어서 2/15의 확률을 뚫으면 된다.

그런데 문제가 있다.

r = read(0, submit, 6);

입력을 받는 부분이 read라서 0~9를 입력하면 48~57의 값이 들어가버린다.

즉 ASCII코드 값으로 1~45의 값을 넣어줘야 한다.

제어문자는 입력하기 귀찮으므로 여기서는 ASCII코드 42값인 *을 사용한다.

lotto@ubuntu:~$./lotto - Select Menu - 1. Play Lotto 2. Help 3. Exit Submit your 6 lotto bytes : ****** Lotto Start! bad luck... - Select Menu - 1. Play Lotto 2. Help 3. Exit Submit your 6 lotto bytes : ******* Lotto Start! sorry mom... I FORGOT to check du************** ## [pwnable] blackjack pwnable에는 재미있는 문제가 많은 것 같다. 특히 게임 형태로 내는 문제가 재밌는데, 오늘은 그 중 가장 쉬운 두 문제를 포스팅할까 한다. Hey! check out this C implementation of blackjack game! I found it online * http://cboard.cprogramming.com/c-programming/114023-simple-blackjack-program.html I like to give my flags to millionares. how much money you got? 첫번째는 blackjack문제이다. 보다시피$1,000,000을 벌면 flag값을 준다는 내용이다.

물론 블랙잭 게임을 좋아하면 순수 게임만으로 풀리지만, 취약점을 찾는 것이 목표이므로 코드를 보겠다.

// Programmer: Vladislav Shulman
// Final Project
// Blackjack

// Feel free to use any and all parts of this program and claim it as your own work

//FINAL DRAFT

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>                //Used for srand((unsigned) time(NULL)) command
#include <process.h>             //Used for system("cls") command

#define club 05                  //Used to print club symbol
#define diamond 04               //Used to print diamond symbol
#define heart 03                 //Used to print heart symbol
#define RESULTS "Blackjack.txt"  //File name is Blackjack

//Global Variables
int k;
int l;
int d;
int won;
int loss;
int cash = 500;
int bet;
int random_card;
int player_total=0;
int dealer_total;

//Function Prototypes
int clubcard();      //Displays Club Card Image
int diamondcard();   //Displays Diamond Card Image
int heartcard();     //Displays Heart Card Image
int randcard();      //Generates random card
int betting();       //Asks user amount to bet
void play();         //Plays game
void dealer();       //Function to play for dealer AI
void stay();         //Function for when user selects 'Stay'
void cash_test();    //Test for if user has cash remaining in purse
void fileresults();  //Prints results into Blackjack.txt file in program directory

//Main Function
int main(void)
{
int choice1;
printf("\n");
printf("\n");
printf("\n");
printf("\n              222                111                            ");
printf("\n            222 222            11111                              ");
printf("\n           222   222          11 111                            ");
printf("\n                222              111                               ");
printf("\n               222               111                           ");
printf("\n");
printf("\n%c%c%c%c%c     %c%c            %c%c         %c%c%c%c%c    %c    %c                ", club, club, club, club, club, spade, spade, diamond, diamond, heart, heart, heart, heart, heart, club, club);
printf("\n%c    %c    %c%c           %c  %c       %c     %c   %c   %c              ", club, club, spade, spade, diamond, diamond, heart, heart, club, club);
printf("\n%c    %c    %c%c          %c    %c     %c          %c  %c               ", club, club, spade, spade, diamond, diamond, heart, club, club);
printf("\n%c%c%c%c%c     %c%c          %c %c%c %c     %c          %c %c              ", club, club, club, club, club, spade, spade, diamond, diamond, diamond, diamond, heart, club, club);
printf("\n%c    %c    %c%c         %c %c%c%c%c %c    %c          %c%c %c             ", club, club, spade, spade, diamond, diamond, diamond, diamond, diamond, diamond, heart, club, club, club);
printf("\n%c     %c   %c%c         %c      %c    %c          %c   %c               ", club, club, spade, spade, diamond, diamond, heart, club, club);
printf("\n%c     %c   %c%c        %c        %c    %c     %c   %c    %c             ", club, club, spade, spade, diamond, diamond, heart, heart, club, club);
printf("\n");
printf("\n                        21                                   ");

printf("\n     %c%c%c%c%c%c%c%c      %c%c         %c%c%c%c%c    %c    %c                ", diamond, diamond, diamond, diamond, diamond, diamond, diamond, diamond, heart, heart, club, club, club, club, club, spade, spade);
printf("\n        %c%c        %c  %c       %c     %c   %c   %c              ", diamond, diamond, heart, heart, club, club, spade, spade);
printf("\n        %c%c       %c    %c     %c          %c  %c               ", diamond, diamond, heart, heart, club, spade, spade);
printf("\n        %c%c       %c %c%c %c     %c          %c %c              ", diamond, diamond, heart, heart, heart, heart, club, spade, spade);
printf("\n        %c%c      %c %c%c%c%c %c    %c          %c%c %c             ", diamond, diamond, heart, heart, heart, heart, heart, heart, club, spade, spade, spade);
printf("\n        %c%c      %c      %c    %c          %c   %c               ", diamond, diamond, heart, heart, club, spade, spade);
printf("\n     %c  %c%c     %c        %c    %c     %c   %c    %c             ", diamond, diamond, diamond, heart, heart, club, spade, spade);
printf("\n      %c%c%c      %c        %c     %c%c%c%c%c    %c     %c            ", diamond, diamond, diamond, heart, heart, club, club, club, club, club, spade, spade);
printf("\n");
printf("\n         222                     111                         ");
printf("\n        222                      111                         ");
printf("\n       222                       111                         ");
printf("\n      222222222222222      111111111111111                       ");
printf("\n      2222222222222222    11111111111111111                         ");
printf("\n");
printf("\n");

printf("\n");
printf("\n");
system("pause");
return(0);
} //end program

void asktitle() // Function for asking player if they want to continue
{
char choice1;
int choice2;

printf("\n                ----------------");
printf("\n                      (Y/N)\n                        ");
scanf("\n%c",&choice1);

while((choice1!='Y') && (choice1!='y') && (choice1!='N') && (choice1!='n')) // If invalid choice entered
{
printf("\n");
printf("Incorrect Choice. Please Enter Y for Yes or N for No.\n");
scanf("%c",&choice1);
}

if((choice1 == 'Y') || (choice1 == 'y')) // If yes, continue. Prints menu.
{
system("cls");
printf("\nEnter 1 to Begin the Greatest Game Ever Played.");
printf("\nEnter 2 to See a Complete Listing of Rules.");
printf("\nEnter 3 to Exit Game. (Not Recommended)");
printf("\nChoice: ");
scanf("%d", &choice2); // Prompts user for choice
if((choice2<1) || (choice2>3)) // If invalid choice entered
{
printf("\nIncorrect Choice. Please enter 1, 2 or 3\n");
scanf("%d", &choice2);
}
switch(choice2) // Switch case for different choices
{
case 1: // Case to begin game
system("cls");

play();

break;

case 2: // Case to see rules
system("cls");
rules();
break;

case 3: // Case to exit game
printf("\nYour day could have been perfect.");
printf("\nHave an almost perfect day!\n\n");
system("pause");
exit(0);
break;

default:
printf("\nInvalid Input");
} // End switch case
} // End if loop

else if((choice1 == 'N') || (choice1 == 'n')) // If no, exit program
{
printf("\nYour day could have been perfect.");
printf("\nHave an almost perfect day!\n\n");
system("pause");
exit(0);
}

return;
} // End function

void rules() //Prints "Rules of Vlad's Blackjack" list
{
char choice1;
int choice2;

printf("\n          ---------------------------");
printf("\nI.");
printf("\n     Thou shalt not question the odds of this game.");
printf("\n      %c This program generates cards at random.", spade);
printf("\n      %c If you keep losing, you are very unlucky!\n", diamond);

printf("\nII.");
printf("\n     Each card has a value.");
printf("\n      %c Number cards 1 to 10 hold a value of their number.", spade);
printf("\n      %c J, Q, and K cards hold a value of 10.", diamond);
printf("\n      %c Ace cards hold a value of 11", club);
printf("\n     The goal of this game is to reach a card value total of 21.\n");

printf("\nIII.");
printf("\n     After the dealing of the first two cards, YOU must decide whether to HIT or STAY.");
printf("\n      %c Staying will keep you safe, hitting will add a card.", spade);
printf("\n     Because you are competing against the dealer, you must beat his hand.");
printf("\n     BUT BEWARE!.");
printf("\n      %c If your total goes over 21, you will LOSE!.", diamond);
printf("\n     But the world is not over, because you can always play again.\n");
printf("\n%c%c%c YOUR RESULTS ARE RECORDED AND FOUND IN SAME FOLDER AS PROGRAM %c%c%c\n", spade, heart, club, club, heart, spade);
printf("\nWould you like to go the previous screen? (I will not take NO for an answer)");
printf("\n                  (Y/N)\n                    ");
scanf("\n%c",&choice1);

while((choice1!='Y') && (choice1!='y') && (choice1!='N') && (choice1!='n')) // If invalid choice entered
{
printf("\n");
printf("Incorrect Choice. Please Enter Y for Yes or N for No.\n");
scanf("%c",&choice1);
}

if((choice1 == 'Y') || (choice1 == 'y')) // If yes, continue. Prints menu.
{
system("cls");
} // End if loop

else if((choice1 == 'N') || (choice1 == 'n')) // If no, convinces user to enter yes
{
system("cls");
printf("\n                 I told you so.\n");
}

return;
} // End function

int clubcard() //Displays Club Card Image
{

srand((unsigned) time(NULL)); //Generates random seed for rand() function
k=rand()%13+1;

if(k<=9) //If random number is 9 or less, print card with that number
{
//Club Card
printf("-------\n");
printf("|%c    |\n", club);
printf("|  %d  |\n", k);
printf("|    %c|\n", club);
printf("-------\n");
}

if(k==10) //If random number is 10, print card with J (Jack) on face
{
//Club Card
printf("-------\n");
printf("|%c    |\n", club);
printf("|  J  |\n");
printf("|    %c|\n", club);
printf("-------\n");
}

if(k==11) //If random number is 11, print card with A (Ace) on face
{
//Club Card
printf("-------\n");
printf("|%c    |\n", club);
printf("|  A  |\n");
printf("|    %c|\n", club);
printf("-------\n");
if(player_total<=10) //If random number is Ace, change value to 11 or 1 depending on dealer total
{
k=11;
}

else
{

k=1;
}
}

if(k==12) //If random number is 12, print card with Q (Queen) on face
{
//Club Card
printf("-------\n");
printf("|%c    |\n", club);
printf("|  Q  |\n");
printf("|    %c|\n", club);
printf("-------\n");
k=10; //Set card value to 10
}

if(k==13) //If random number is 13, print card with K (King) on face
{
//Club Card
printf("-------\n");
printf("|%c    |\n", club);
printf("|  K  |\n");
printf("|    %c|\n", club);
printf("-------\n");
k=10; //Set card value to 10
}
return k;
}// End function

int diamondcard() //Displays Diamond Card Image
{

srand((unsigned) time(NULL)); //Generates random seed for rand() function
k=rand()%13+1;

if(k<=9) //If random number is 9 or less, print card with that number
{
//Diamond Card
printf("-------\n");
printf("|%c    |\n", diamond);
printf("|  %d  |\n", k);
printf("|    %c|\n", diamond);
printf("-------\n");
}

if(k==10) //If random number is 10, print card with J (Jack) on face
{
//Diamond Card
printf("-------\n");
printf("|%c    |\n", diamond);
printf("|  J  |\n");
printf("|    %c|\n", diamond);
printf("-------\n");
}

if(k==11) //If random number is 11, print card with A (Ace) on face
{
//Diamond Card
printf("-------\n");
printf("|%c    |\n", diamond);
printf("|  A  |\n");
printf("|    %c|\n", diamond);
printf("-------\n");
if(player_total<=10) //If random number is Ace, change value to 11 or 1 depending on dealer total
{
k=11;
}

else
{
k=1;
}
}

if(k==12) //If random number is 12, print card with Q (Queen) on face
{
//Diamond Card
printf("-------\n");
printf("|%c    |\n", diamond);
printf("|  Q  |\n");
printf("|    %c|\n", diamond);
printf("-------\n");
k=10; //Set card value to 10
}

if(k==13) //If random number is 13, print card with K (King) on face
{
//Diamond Card
printf("-------\n");
printf("|%c    |\n", diamond);
printf("|  K  |\n");
printf("|    %c|\n", diamond);
printf("-------\n");
k=10; //Set card value to 10
}
return k;
}// End function

int heartcard() //Displays Heart Card Image
{

srand((unsigned) time(NULL)); //Generates random seed for rand() function
k=rand()%13+1;

if(k<=9) //If random number is 9 or less, print card with that number
{
//Heart Card
printf("-------\n");
printf("|%c    |\n", heart);
printf("|  %d  |\n", k);
printf("|    %c|\n", heart);
printf("-------\n");
}

if(k==10) //If random number is 10, print card with J (Jack) on face
{
//Heart Card
printf("-------\n");
printf("|%c    |\n", heart);
printf("|  J  |\n");
printf("|    %c|\n", heart);
printf("-------\n");
}

if(k==11) //If random number is 11, print card with A (Ace) on face
{
//Heart Card
printf("-------\n");
printf("|%c    |\n", heart);
printf("|  A  |\n");
printf("|    %c|\n", heart);
printf("-------\n");
if(player_total<=10) //If random number is Ace, change value to 11 or 1 depending on dealer total
{
k=11;
}

else
{
k=1;
}
}

if(k==12) //If random number is 12, print card with Q (Queen) on face
{
//Heart Card
printf("-------\n");
printf("|%c    |\n", heart);
printf("|  Q  |\n");
printf("|    %c|\n", heart);
printf("-------\n");
k=10; //Set card value to 10
}

if(k==13) //If random number is 13, print card with K (King) on face
{
//Heart Card
printf("-------\n");
printf("|%c    |\n", heart);
printf("|  K  |\n");
printf("|    %c|\n", heart);
printf("-------\n");
k=10; //Set card value to 10
}
return k;
} // End Function

{

srand((unsigned) time(NULL)); //Generates random seed for rand() function
k=rand()%13+1;

if(k<=9) //If random number is 9 or less, print card with that number
{
printf("-------\n");
printf("|  %d  |\n", k);
printf("-------\n");
}

if(k==10) //If random number is 10, print card with J (Jack) on face
{
printf("-------\n");
printf("|  J  |\n");
printf("-------\n");
}

if(k==11) //If random number is 11, print card with A (Ace) on face
{
printf("-------\n");
printf("|  A  |\n");
printf("-------\n");
if(player_total<=10) //If random number is Ace, change value to 11 or 1 depending on dealer total
{
k=11;
}

else
{
k=1;
}
}

if(k==12) //If random number is 12, print card with Q (Queen) on face
{
printf("-------\n");
printf("|  Q  |\n");
printf("-------\n");
k=10; //Set card value to 10
}

if(k==13) //If random number is 13, print card with K (King) on face
{
printf("-------\n");
printf("|  K  |\n");
printf("-------\n");
k=10; //Set card value to 10
}
return k;
} // End Function

int randcard() //Generates random card
{

srand((unsigned) time(NULL)); //Generates random seed for rand() function
random_card = rand()%4+1;

if(random_card==1)
{
clubcard();
l=k;
}

if(random_card==2)
{
diamondcard();
l=k;
}

if(random_card==3)
{
heartcard();
l=k;
}

if(random_card==4)
{
l=k;
}
return l;
} // End Function

void play() //Plays game
{

int p=0; // holds value of player_total
int i=1; // counter for asking user to hold or stay (aka game turns)
char choice3;

cash = cash;
cash_test();
printf("\nCash: $%d\n",cash); //Prints amount of cash user has randcard(); //Generates random card player_total = p + l; //Computes player total p = player_total; printf("\nYour Total is %d\n", p); //Prints player total dealer(); //Computes and prints dealer total betting(); //Prompts user to enter bet amount while(i<=21) //While loop used to keep asking user to hit or stay at most twenty-one times // because there is a chance user can generate twenty-one consecutive 1's { if(p==21) //If user total is 21, win { printf("\nUnbelievable! You Win!\n"); won = won+1; cash = cash+bet; printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss); dealer_total=0; askover(); } if(p>21) //If player total is over 21, loss { printf("\nWoah Buddy, You Went WAY over.\n"); loss = loss+1; cash = cash - bet; printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss); dealer_total=0; askover(); } if(p<=21) //If player total is less than 21, ask to hit or stay { printf("\n\nWould You Like to Hit or Stay?"); scanf("%c", &choice3); while((choice3!='H') && (choice3!='h') && (choice3!='S') && (choice3!='s')) // If invalid choice entered { printf("\n"); printf("Please Enter H to Hit or S to Stay.\n"); scanf("%c",&choice3); } if((choice3=='H') || (choice3=='h')) // If Hit, continues { randcard(); player_total = p + l; p = player_total; printf("\nYour Total is %d\n", p); dealer(); if(dealer_total==21) //Is dealer total is 21, loss { printf("\nDealer Has the Better Hand. You Lose.\n"); loss = loss+1; cash = cash - bet; printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss); dealer_total=0; askover(); } if(dealer_total>21) //If dealer total is over 21, win { printf("\nDealer Has Went Over!. You Win!\n"); won = won+1; cash = cash+bet; printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss); dealer_total=0; askover(); } } if((choice3=='S') || (choice3=='s')) // If Stay, does not continue { printf("\nYou Have Chosen to Stay at %d. Wise Decision!\n", player_total); stay(); } } i++; //While player total and dealer total are less than 21, re-do while loop } // End While Loop } // End Function void dealer() //Function to play for dealer AI { int z; if(dealer_total<17) { srand((unsigned) time(NULL) + 1); //Generates random seed for rand() function z=rand()%13+1; if(z<=10) //If random number generated is 10 or less, keep that value { d=z; } if(z>11) //If random number generated is more than 11, change value to 10 { d=10; } if(z==11) //If random number is 11(Ace), change value to 11 or 1 depending on dealer total { if(dealer_total<=10) { d=11; } else { d=1; } } dealer_total = dealer_total + d; } printf("\nThe Dealer Has a Total of %d", dealer_total); //Prints dealer total } // End Function void stay() //Function for when user selects 'Stay' { dealer(); //If stay selected, dealer continues going if(dealer_total>=17) { if(player_total>=dealer_total) //If player's total is more than dealer's total, win { printf("\nUnbelievable! You Win!\n"); won = won+1; cash = cash+bet; printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss); dealer_total=0; askover(); } if(player_total<dealer_total) //If player's total is less than dealer's total, loss { printf("\nDealer Has the Better Hand. You Lose.\n"); loss = loss+1; cash = cash - bet; printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss); dealer_total=0; askover(); } if(dealer_total>21) //If dealer's total is more than 21, win { printf("\nUnbelievable! You Win!\n"); won = won+1; cash = cash+bet; printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss); dealer_total=0; askover(); } } else { stay(); } } // End Function void cash_test() //Test for if user has cash remaining in purse { if (cash <= 0) //Once user has zero remaining cash, game ends and prompts user to play again { printf("You Are Bankrupt. Game Over"); cash = 500; askover(); } } // End Function 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

void askover() // Function for asking player if they want to play again
{
char choice1;

printf("\nWould You Like To Play Again?");
printf("\nPlease Enter Y for Yes or N for No\n");
scanf("\n%c",&choice1);

while((choice1!='Y') && (choice1!='y') && (choice1!='N') && (choice1!='n')) // If invalid choice entered
{
printf("\n");
printf("Incorrect Choice. Please Enter Y for Yes or N for No.\n");
scanf("%c",&choice1);
}

if((choice1 == 'Y') || (choice1 == 'y')) // If yes, continue.
{
system("cls");
play();
}

else if((choice1 == 'N') || (choice1 == 'n')) // If no, exit program
{
fileresults();
printf("\nBYE!!!!\n\n");
system("pause");
exit(0);
}
return;
} // End function

void fileresults() //Prints results into Blackjack.txt file in program directory
{
FILE *fpresults; //File pointer is fpresults
fpresults = fopen(RESULTS, "w"); //Creates file and writes into it
if(fpresults == NULL) // what to do if file missing from directory
{
printf("\nError: File Missing\n");
system("pause");
exit(1);
}
else
{
fprintf(fpresults,"\n\t RESULTS");
fprintf(fpresults,"\n\t---------\n");
fprintf(fpresults,"\nYou Have Won %d Times\n", won);
fprintf(fpresults,"\nYou Have Lost %d Times\n", loss);
fprintf(fpresults,"\nKeep Playing and Set an All-Time Record!");
}
fclose(fpresults);
return;
} // End Function

길다.

취약점과 별 관련이 없어보이는 부분을 제거해보겠다.

int main(void){
}

void asktitle() // Function for asking player if they want to continue
{
char choice1;
int choice2;

scanf("\n%c",&choice1);

while((choice1!='Y') && (choice1!='y') && (choice1!='N') && (choice1!='n')){
printf("Incorrect Choice. Please Enter Y for Yes or N for No.\n");
scanf("%c",&choice1);
}

if((choice1 == 'Y') || (choice1 == 'y')){
printf("\nChoice: ");
scanf("%d", &choice2); // Prompts user for choice
if((choice2<1) || (choice2>3)) // If invalid choice entered
{
printf("\nIncorrect Choice. Please enter 1, 2 or 3\n");
scanf("%d", &choice2);
}
switch(choice2) // Switch case for different choices
{
case 1: // Case to begin game
play();
break;
case 2: // Case to see rules
rules();
break;
case 3: // Case to exit game
exit(0);
break;
default:
printf("\nInvalid Input");
} // End switch case
} // End if loop

else if((choice1 == 'N') || (choice1 == 'n')){
exit(0);
}

return;
} // End function

int randcard() //Generates random card
{
srand((unsigned) time(NULL)); //Generates random seed for rand() function
random_card = rand()%4+1;

return l;
} // End Function

void play() //Plays game
{
cash_test();
randcard(); //Generates random card
dealer(); //Computes and prints dealer total
betting(); //Prompts user to enter bet amount

while(i<=21) //While loop used to keep asking user to hit or stay at most twenty-one times
//  because there is a chance user can generate twenty-one consecutive 1's
{
if(p==21) //If user total is 21, win
{
printf("\nUnbelievable! You Win!\n");
won = won+1;
cash = cash+bet;
printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
dealer_total=0;
}

if(p>21) //If player total is over 21, loss
{
printf("\nWoah Buddy, You Went WAY over.\n");
loss = loss+1;
cash = cash - bet;
printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
dealer_total=0;
}

if(p<=21) //If player total is less than 21, ask to hit or stay
{
printf("\n\nWould You Like to Hit or Stay?");

scanf("%c", &choice3);
while((choice3!='H') && (choice3!='h') && (choice3!='S') && (choice3!='s')) // If invalid choice entered
{
printf("\n");
printf("Please Enter H to Hit or S to Stay.\n");
scanf("%c",&choice3);
}

if((choice3=='H') || (choice3=='h')) // If Hit, continues
{
randcard();
player_total = p + l;
p = player_total;
dealer();
if(dealer_total==21) //Is dealer total is 21, loss
{
printf("\nDealer Has the Better Hand. You Lose.\n");
loss = loss+1;
cash = cash - bet;
printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
dealer_total=0;
}

if(dealer_total>21) //If dealer total is over 21, win
{
printf("\nDealer Has Went Over!. You Win!\n");
won = won+1;
cash = cash+bet;
printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
dealer_total=0;
}
}
if((choice3=='S') || (choice3=='s')) // If Stay, does not continue
{
printf("\nYou Have Chosen to Stay at %d. Wise Decision!\n", player_total);
stay();
}
}
i++; //While player total and dealer total are less than 21, re-do while loop
} // End While Loop
} // End Function

void dealer() //Function to play for dealer AI
{
int z;

if(dealer_total<17)
{
srand((unsigned) time(NULL) + 1); //Generates random seed for rand() function
z=rand()%13+1;
if(z<=10) //If random number generated is 10 or less, keep that value
{
d=z;

}

if(z>11) //If random number generated is more than 11, change value to 10
{
d=10;
}

if(z==11) //If random number is 11(Ace), change value to 11 or 1 depending on dealer total
{
if(dealer_total<=10)
{
d=11;
}

else
{
d=1;
}
}
dealer_total = dealer_total + d;
}

printf("\nThe Dealer Has a Total of %d", dealer_total); //Prints dealer total

} // End Function

void stay() //Function for when user selects 'Stay'
{
dealer(); //If stay selected, dealer continues going
if(dealer_total>=17)
{
if(player_total>=dealer_total) //If player's total is more than dealer's total, win
{
printf("\nUnbelievable! You Win!\n");
won = won+1;
cash = cash+bet;
printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
dealer_total=0;
}
if(player_total<dealer_total) //If player's total is less than dealer's total, loss
{
printf("\nDealer Has the Better Hand. You Lose.\n");
loss = loss+1;
cash = cash - bet;
printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
dealer_total=0;
}
if(dealer_total>21) //If dealer's total is more than 21, win
{
printf("\nUnbelievable! You Win!\n");
won = won+1;
cash = cash+bet;
printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
dealer_total=0;
}
}
else
{
stay();
}

} // End Function

void cash_test() //Test for if user has cash remaining in purse
{
if (cash <= 0) //Once user has zero remaining cash, game ends and prompts user to play again
{
printf("You Are Bankrupt. Game Over");
cash = 500;
}
} // End Function

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 void askover() // Function for asking player if they want to play again { char choice1; printf("\nWould You Like To Play Again?"); printf("\nPlease Enter Y for Yes or N for No\n"); scanf("\n%c",&choice1); while((choice1!='Y') && (choice1!='y') && (choice1!='N') && (choice1!='n')) // If invalid choice entered { printf("\n"); printf("Incorrect Choice. Please Enter Y for Yes or N for No.\n"); scanf("%c",&choice1); } if((choice1 == 'Y') || (choice1 == 'y')) // If yes, continue. { system("cls"); play(); } else if((choice1 == 'N') || (choice1 == 'n')) // If no, exit program { fileresults(); printf("\nBYE!!!!\n\n"); system("pause"); exit(0); } return; } // End function void fileresults(){ FILE *fpresults; //File pointer is fpresults fpresults = fopen(RESULTS, "w"); //Creates file and writes into it if(fpresults == NULL) // what to do if file missing from directory { printf("\nError: File Missing\n"); system("pause"); exit(1); } fclose(fpresults); return; } // End Function 간단하게 요약하면 게임 시작을 하면 패배조건을 체크(cash_test)를 하고 카드를 섞은다음(randcard) 딜러가 한장 뽑고(dealer) 유저가 배팅을 한 다음(betting) 서로 게임을 진행한다. 이제 하나하나 분석해보자. 먼저 randcard 함수를 보면 srand((unsigned) time(NULL)); 의 존재때문에 [pwnable] random 문제 때처럼 랜덤값을 이용할 순 없다. 다음 dealer를 보면 합이 17 이상부터는 카드를 절대 뽑지 않는다는걸 알 수 있다. 그럼 상대가 17 이상이고 내가 그 수 보다 같거나 클 때(stay) 스테이를 하면 무조건 이긴다는걸 알 수 있다. 그런데 이거가지고 100만달러를 벌기엔 많이 부족해보인다. 그 다음 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

?? 뭔가 예외처리를 한거같긴 한데 while이 아니라 if다.

그럼 두 번째부터는 예외처리가 되지 않는다는거다.

즉, 내 소지금에 상관없이 배팅을 무한대로 할 수 있다는 것이다.

그럼 이제 배팅금액을 $1,000,000 이상으로 잡고 이길때까지 몇 판만 해주면 된다. Cash:$500
-------
|C    |
|  2  |
|    C|
-------

The Dealer Has a Total of 8

Enter Bet: \$10000000

You cannot bet more money than you have.
Enter Bet: 10000000

Would You Like to Hit or Stay?
Please Enter H to Hit or S to Stay.
H
-------
|C    |
|  5  |
|    C|
-------

The Dealer Has a Total of 12

Would You Like to Hit or Stay?
Please Enter H to Hit or S to Stay.
H
-------
|S    |
|  Q  |
|    S|
-------

The Dealer Has a Total of 17

Would You Like to Hit or Stay?
Please Enter H to Hit or S to Stay.
S

You Have Chosen to Stay at 17. Wise Decision!

The Dealer Has a Total of 17
Unbelievable! You Win!

You have 1 Wins and 0 Losses. Awesome!

Would You Like To Play Again?
Please Enter Y for Yes or N for No
Y

YaY_I_AM_A_MILL***********