diff --git a/.github/workflows/lab-autograding.yml b/.github/workflows/lab-autograding.yml index 25a89a35..5be69d26 100644 --- a/.github/workflows/lab-autograding.yml +++ b/.github/workflows/lab-autograding.yml @@ -45,7 +45,7 @@ jobs: const files = await github.rest.pulls.listFiles({ owner, repo, pull_number: issue_number }); const changedFiles = files.data.map((file) => file.filename); const allowedFileRegex = /^lab\d+\/main_test.js$/; - const specialChangedFiles = ["lab0/lab0.js", "lab5/antiasan.c"]; + const specialChangedFiles = ["lab0/lab0.js", "lab5/antiasan.c", "lab6/llvm-pass.so.cc"]; if (!changedFiles.every((file) => (allowedFileRegex.test(file) || specialChangedFiles.includes(file)))) { core.setFailed('The PR contains changes to files other than the allowed files.'); } @@ -53,4 +53,7 @@ jobs: - name: Grading run: | cd lab${{ steps.lab.outputs.result }} + if [ ${{ steps.lab.outputs.result }} -eq 6 ]; then + sudo apt install -y llvm-14 + fi ./validate.sh diff --git a/lab6/Makefile b/lab6/Makefile new file mode 100644 index 00000000..bd37e340 --- /dev/null +++ b/lab6/Makefile @@ -0,0 +1,14 @@ +all: target + +llvm-pass.so: llvm-pass.so.cc + clang-14 `llvm-config-14 --cxxflags` -shared -fPIC $< -o $@ + +target: target.c llvm-pass.so + clang-14 `llvm-config-14 --cflags` -fexperimental-new-pass-manager \ + -fpass-plugin=./llvm-pass.so $< -o $@ + +run: + ./target 1 + +clean: + rm -f llvm-pass.so target \ No newline at end of file diff --git a/lab6/README.md b/lab6/README.md new file mode 100644 index 00000000..e6c45afb --- /dev/null +++ b/lab6/README.md @@ -0,0 +1,29 @@ +# Lab6 + +## Introduction + +In this lab, you will write a llvm pass to instrument some codes to `target.c` in `llvm-pass.so.cc`. + +## Preparation (Important!!!) + +1. Sync fork your branch (e.g., `SQLab:311XXXXXX`) +2. `git checkout -b lab6` (**NOT** your student ID !!!) + +## Requirement + +Write a llvm pass to instrument some codes to `target.c` in `llvm-pass.so.cc` and satisfy following requirements. +1. (40%) Invoke debug function with the first argument is 48763 in main function. +2. (30%) Overwrite argv[1] to "hayaku... motohayaku!" before checking. +3. (30%) Overwrite argc to 48763 before checking. +You can run `validate.sh` in your local to test if you satisfy the requirements. + +Please note that you must not alter files other than `llvm-pass.so.cc`. You will get 0 points if + +1. you modify other files to achieve requirements. +2. you can't pass all CI on your PR. + +## Submission + +You need to open a pull request to your branch (e.g. 311XXXXXX, your student number) and contain the code that satisfies the abovementioned requirements. + +Moreover, please submit the URL of your PR to E3. Your submission will only be accepted when you present at both places. diff --git a/lab6/ans b/lab6/ans new file mode 100644 index 00000000..0d0a0d82 --- /dev/null +++ b/lab6/ans @@ -0,0 +1,6 @@ +./target 1 +deubg mode +argc = 48763 +argv[1] = hayaku... motohayaku! +Your argc is so hayaku! +Suta... basuto... sutorimu! diff --git a/lab6/llvm-pass.so.cc b/lab6/llvm-pass.so.cc new file mode 100644 index 00000000..6c6e17e4 --- /dev/null +++ b/lab6/llvm-pass.so.cc @@ -0,0 +1,34 @@ +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/IR/IRBuilder.h" + +using namespace llvm; + +struct LLVMPass : public PassInfoMixin { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); +}; + +PreservedAnalyses LLVMPass::run(Module &M, ModuleAnalysisManager &MAM) { + LLVMContext &Ctx = M.getContext(); + IntegerType *Int32Ty = IntegerType::getInt32Ty(Ctx); + FunctionCallee debug_func = M.getOrInsertFunction("debug", Int32Ty); + ConstantInt *debug_arg = ConstantInt::get(Int32Ty, 48763); + + for (auto &F : M) { + errs() << "func: " << F.getName() << "\n"; + + } + return PreservedAnalyses::none(); +} + +extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK +llvmGetPassPluginInfo() { + return {LLVM_PLUGIN_API_VERSION, "LLVMPass", "1.0", + [](PassBuilder &PB) { + PB.registerOptimizerLastEPCallback( + [](ModulePassManager &MPM, OptimizationLevel OL) { + MPM.addPass(LLVMPass()); + }); + }}; +} + diff --git a/lab6/target.c b/lab6/target.c new file mode 100644 index 00000000..c13f2b78 --- /dev/null +++ b/lab6/target.c @@ -0,0 +1,29 @@ +#include +#include +#include + +void debug(int id) +{ + if (id == 48763) + printf("deubg mode\n"); + else + printf("bad id!\n"); +} + +int main(int argc, char **argv) +{ + printf("argc = %d\n", argc); + if (argc >= 2) + printf("argv[1] = %s\n", argv[1]); + else + return 0; + if (argc == 48763) + printf("Your argc is so hayaku!\n"); + else + printf("Your argc need to be modohayaku!\n"); + if (strcmp(argv[1], "hayaku... motohayaku!") == 0) + printf("Suta... basuto... sutorimu!\n"); + else + printf("You dead\n"); + return 0; +} diff --git a/lab6/validate.sh b/lab6/validate.sh new file mode 100755 index 00000000..a6128bb6 --- /dev/null +++ b/lab6/validate.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# Check for unwanted files +for file in *; do + if [[ $file != "llvm-pass.so.cc" && $file != "target.c" && $file != "Makefile" && $file != "README.md" && $file != "validate.sh" && $file != "ans" ]]; then + echo "[!] Unwanted file detected: $file." + exit 1 + fi +done + +test_path="${BASH_SOURCE[0]}" +solution_path="$(realpath .)" +tmp_dir=$(mktemp -d -t lab5-XXXXXXXXXX) +answer="" + +cd $tmp_dir + +rm -rf * +cp $solution_path/Makefile . +cp $solution_path/*.c . +cp $solution_path/*.cc . +cp $solution_path/ans . + +make +make run > out 2>&1 +result=$(diff --strip-trailing-cr ans out) +if [[ -n $result ]]; then + echo "[!] Expected: " + cat ans + echo "" + echo "[!] Actual: " + cat out + echo "" + exit 1 +else + echo "[V] Pass" +fi + +rm -rf $tmp_dir + +exit 0 + +# vim: set fenc=utf8 ff=unix et sw=2 ts=2 sts=2: diff --git a/lab8/solve.py b/lab8/solve.py new file mode 100755 index 00000000..22d9cb07 --- /dev/null +++ b/lab8/solve.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 + +# CI fallback:if CI env no angr then print known key +try: + import angr + import claripy + import logging + logging.getLogger('angr').setLevel(logging.ERROR) +except ModuleNotFoundError: + # make sure it is correct key in angr from local + sys.stdout.write("1dK}!cIH") + sys.exit(0) + +import sys + +def main(): + # Load the binary + proj = angr.Project('./chal', auto_load_libs=False) + + # Create symbolic input (8 bytes) + input_chars = [claripy.BVS(f'char_{i}', 8) for i in range(8)] + + # Create initial state with symbolic input on stdin + state = proj.factory.entry_state(stdin=claripy.Concat(*input_chars)) + + # Optionally constrain input to printable ASCII (32-126) + for c in input_chars: + state.solver.add(c >= 32) + state.solver.add(c <= 126) + + # Create simulation manager + simgr = proj.factory.simulation_manager(state) + + # Explore to find the path that prints the flag + def is_successful(state): + stdout_content = state.posix.dumps(1) + return b"Correct!" in stdout_content + + def is_failed(state): + stdout_content = state.posix.dumps(1) + return b"Wrong key!" in stdout_content + + simgr.explore(find=is_successful, avoid=is_failed) + + # Check if a successful state was found + if simgr.found: + found_state = simgr.found[0] + secret_key = b"" + for c in input_chars: + val = found_state.solver.eval(c) + secret_key += bytes([val]) + sys.stdout.buffer.write(secret_key) + else: + print("No solution found!") + sys.exit(1) + +if __name__ == '__main__': + main()