Initial commit

This commit is contained in:
2025-04-12 08:26:23 +08:00
commit aa66855054
57 changed files with 1702 additions and 0 deletions

3
.gdb_history Normal file
View File

@@ -0,0 +1,3 @@
exit
exit
exit

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
sdb
*.o

18
Makefile Normal file
View File

@@ -0,0 +1,18 @@
.PHONY: all debug clean test
all: sdb
sdb: $(patsubst %.c,%.o,$(wildcard *.c))
gcc -o $@ $^ -lcapstone -std=gnu17 -g -fsanitize=address,undefined -fanalyzer
%.o: %.c
gcc -o $@ -c $^ -std=gnu17 -Wall -Wextra \
-g -fsanitize=address,undefined -fanalyzer \
-Wno-unused-value #-DDEBUG
clean:
- rm -f sdb *.o
make -C test clean
test: sdb
make -C test_case

BIN
hw3_testcase.zip Normal file

Binary file not shown.

37
logger.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
#include <stdio.h>
#include <unistd.h>
#define ANSI_ESC_RED "\x1B[31m"
#define ANSI_ESC_GREEN "\x1B[32m"
#define ANSI_ESC_YELLOW "\x1B[33m"
#define ANSI_ESC_BLUE "\x1B[34m"
#define ANSI_ESC_MAGENTA "\x1B[35m"
#define ANSI_ESC_CYAN "\x1B[36m"
#define ANSI_ESC_COLOR_RESET "\x1B[m"
#define ANSI_ESC_CLEAR "\x1B[2J"
#define ANSI_ESC_CURSOR_RESET "\x1B[;H"
#ifdef DEBUG
#define PRINT(file, color, prompt, format, ...) \
fprintf(file, "%s%s", color, prompt), \
fprintf(file, format, ##__VA_ARGS__), \
fprintf(file, "%s", ANSI_ESC_COLOR_RESET)
#define ERROR(format, ...) \
PRINT(stderr, ANSI_ESC_RED, "[ERROR] ", format, ##__VA_ARGS__)
#define DEBUG(format, ...) \
PRINT(stderr, ANSI_ESC_YELLOW, "[DEBUG] ", format, ##__VA_ARGS__)
#else
#define PRINT(file, color, prompt, format, ...) \
fprintf(file, "%s", prompt), \
fprintf(file, format, ##__VA_ARGS__)
#define ERROR(format, ...)
#define DEBUG(format, ...)
#endif
#define INFO(format, ...) \
PRINT(stdout, ANSI_ESC_CYAN, "** ", format, ##__VA_ARGS__)
#define OUTPUT(format, ...) \
PRINT(stdout, ANSI_ESC_COLOR_RESET, "", format, ##__VA_ARGS__)

116
main.c Normal file
View File

@@ -0,0 +1,116 @@
#include "sdb.h"
#include "vector.h"
#include "logger.h"
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/limits.h>
static inline enum instruction prompt(void)
{
static char *input;
static size_t input_len;
OUTPUT("(sdb) ");
getline(&input, &input_len, stdin);
char *op = strtok(input, " \t\n");
if (op == NULL) return INST_NOP;
if (strcmp(op, "exit") == 0) return INST_EXIT;
if (strcmp(op, "load") == 0) return INST_LOAD;
if (strcmp(op, "show") == 0) return INST_SHOW;
if (strcmp(op, "info") == 0) return INST_INFO;
if (strcmp(op, "break") == 0) return INST_BREAK;
if (strcmp(op, "delete") == 0) return INST_DELETE;
if (strcmp(op, "patch") == 0) return INST_PATCH;
if (strcmp(op, "si") == 0) return INST_SI;
if (strcmp(op, "cont") == 0) return INST_CONT;
if (strcmp(op, "syscall") == 0) return INST_SYSCALL;
return INST_INVALID;
}
int main(int argc, char *argv[])
{
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
char *filename = "";
if (argc > 1) {
filename = malloc(strlen(argv[1]) + 1);
strcpy(filename, argv[1]);
if (access(filename, F_OK) != 0) {
perror("main file open");
exit(1);
}
}
if (access(filename, F_OK) != 0) {
load_retry:
enum instruction op = prompt();
switch (op) {
case INST_NOP:
goto load_retry;
case INST_EXIT:
goto exit;
case INST_LOAD:
inst_load(&filename);
if (access(filename, F_OK) == 0)
break;
else {
INFO("file invalid\n");
goto load_retry;
}
default:
INFO("please load a program first.\n");
goto load_retry;
}
}
DEBUG("filename = %s\n", filename);
run(filename);
sync_regs();
disassemble_addr = regs.rip;
disassemble();
for (;;) {
enum instruction op = prompt();
DEBUG("op = 0x%x\n", (int)op);
switch (op) {
case INST_NOP: break;
case INST_EXIT: goto exit;
case INST_SHOW: disassemble(); break;
case INST_INFO: inst_info(); break;
case INST_BREAK: inst_break(); break;
case INST_DELETE: inst_delete(); break;
case INST_PATCH: inst_patch(); break;
case INST_SI: inst_si(); disassemble(); break;
case INST_CONT: inst_cont(); disassemble(); break;
case INST_SYSCALL: inst_syscall(); disassemble(); break;
default:
INFO("invalid command\n");
}
DEBUG("disassemble_addr = %p\n", (void *)disassemble_addr);
if (disassemble_addr == 0x00)
goto exit;
}
exit:
free(filename);
free(bps);
return 0;
}

410
sdb.c Normal file
View File

@@ -0,0 +1,410 @@
#include "sdb.h"
#include "logger.h"
#include "vector.h"
#include <stdlib.h>
#include <string.h>
#include <capstone/capstone.h>
#include <sys/user.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
int child;
int status;
struct user_regs_struct regs;
uint64_t disassemble_addr;
long syscall_nr = 0xffff;
void sync_regs(void)
{
if (ptrace(PTRACE_GETREGS, child, NULL, &regs) != 0) {
ERROR("sync_regs ptrace getregs\n");
perror("sync_regs");
exit(1);
}
}
uint8_t poke(uint64_t addr, uint8_t data)
{
uint64_t ret = ptrace(PTRACE_PEEKTEXT, child, addr, NULL);
ptrace(PTRACE_POKETEXT, child, addr, (ret & ~0xff) | data);
return ret & 0xff;
}
void run(const char *filename)
{
child = fork();
if (child < 0) {
ERROR("run fork failed\n");
perror("run fork");
exit(1);
}
if (child == 0) {
DEBUG("forked\n");
if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) {
perror("run traceme");
exit(1);
}
execl(filename, filename, NULL);
perror("run execl");
}
if (waitpid(child, &status, 0) < 0) {
perror("run waitpid");
exit(1);
}
if (WIFSTOPPED(status) == 0) {
perror("run stopped");
exit(1);
}
ptrace(PTRACE_SETOPTIONS, child, 0,
PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD);
sync_regs();
INFO("program '%s' loaded. entry point %p.\n", filename, (void *)regs.rip);
}
void disassemble()
{
if (disassemble_addr == 0x00) return;
const uint64_t rip = disassemble_addr;
long ret;
uint8_t code[64], *ptr = (uint8_t *)&ret;
for (int i = 0; i < 8; i++) {
ret = ptrace(PTRACE_PEEKTEXT, child, rip + (i << 3), NULL);
for (int j = 0; j < 8; j++)
code[i << 3 | j] = ptr[j];
// DEBUG("\n");
}
for (int i = 0; i < bps_len; i++)
if (bps[i].addr && rip <= bps[i].addr && bps[i].addr < rip + 64)
code[bps[i].addr - rip] = bps[i].data;
csh handle;
if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) {
perror("disassemble cs_open");
exit(1);
}
cs_insn *insn;
int count = cs_disasm(handle, code, sizeof(code) - 1, rip, 0, &insn);
if (count > 0) {
for (int i = 0; i < INSTRUCTION_COUNT; i++) {
if (insn[i].size == 2 &&
insn[i].bytes[0] == 0 &&
insn[i].bytes[1] == 0) {
INFO("the address is out of the range of the text section.\n");
break;
}
OUTPUT("%12lx: ", insn[i].address);
char insn_buf[25] = "", *insn_buf_ptr = insn_buf;
for (int j = 0; j < insn[i].size; j++)
insn_buf_ptr += sprintf(insn_buf_ptr, "%02x ",
(uint8_t)insn[i].bytes[j]);
OUTPUT("%-24s%-10s %s\n", insn_buf, insn[i].mnemonic, insn[i].op_str);
}
cs_free(insn, count);
} else {
perror("disassemble");
exit(1);
}
cs_close(&handle);
}
void inst_load(char **filename)
{
char *token = strtok(NULL, " \t\n");
if (token == NULL) {
perror("inst_load");
disassemble_addr = 0x00;
return;
}
*filename = malloc(strlen(token) + 1);
strcpy(*filename, token);
}
void inst_si(void)
{
if (!WIFSTOPPED(status)) {
ERROR("program not running.\n");
perror("inst_si not running");
disassemble_addr = 0x00;
return;
}
syscall_nr = 0xffff;
sync_regs();
uint64_t rip = regs.rip;
DEBUG("rip = %lx\n", rip);
const struct bps_node *bp = find(rip);
if (bp)
poke(bp->addr, bp->data);
ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
waitpid(child, &status, 0);
if (bp)
poke(bp->addr, 0xcc);
sync_regs();
rip = regs.rip, bp = find(rip);
if (bp)
INFO("hit a breakpoint at %p.\n", (void *)rip);
if (!WIFSTOPPED(status)) {
INFO("the target program terminated.\n");
disassemble_addr = 0x00;
} else {
sync_regs();
disassemble_addr = regs.rip;
}
}
void inst_cont(void)
{
if (!WIFSTOPPED(status)) {
ERROR("program not running.\n");
perror("inst_cont not running");
exit(1);
}
syscall_nr = 0xffff;
sync_regs();
uint64_t rip = regs.rip;
DEBUG("rip = %lx\n", rip);
const struct bps_node *bp = find(rip);
if (bp) {
poke(bp->addr, bp->data);
ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
waitpid(child, &status, 0);
poke(bp->addr, 0xcc);
}
ptrace(PTRACE_CONT, child, NULL, NULL);
waitpid(child, &status, 0);
if (!WIFSTOPPED(status)) {
INFO("the target program terminated.\n");
disassemble_addr = 0x00;
} else {
sync_regs();
rip = regs.rip;
bp = find(rip - 1);
if (bp == NULL) {
perror("inst_cont bp = NULL\n");
exit(1);
}
INFO("hit a breakpoint at %p.\n", (void *)(rip - 1));
poke(bp->addr, bp->data);
regs.rip -= 1;
ptrace(PTRACE_SETREGS, child, 0, &regs);
poke(bp->addr, 0xcc);
sync_regs();
disassemble_addr = regs.rip;
}
}
void inst_info(void)
{
char *op = strtok(NULL, " \t\n");
if (op == NULL)
goto inst_info_invalid;
if (strcmp(op, "reg") == 0)
inst_info_reg();
else if (strcmp(op, "break") == 0)
inst_info_break();
else
goto inst_info_invalid;
return;
inst_info_invalid:
ERROR("invalid command\n");
INFO("Command: info [reg | break]\n");
}
void inst_info_reg(void)
{
sync_regs();
#define OUTPUT_REGS(a, b, c) \
OUTPUT("$%-7s 0x%016lx\t$%-7s 0x%016lx\t$%-7s 0x%016lx\n", \
#a, (unsigned long)regs.a, \
#b, (unsigned long)regs.b, \
#c, (unsigned long)regs.c)
OUTPUT_REGS(rax, rbx, rcx);
OUTPUT_REGS(rdx, rsi, rdi);
OUTPUT_REGS(rbp, rsp, r8);
OUTPUT_REGS( r9, r10, r11);
OUTPUT_REGS(r12, r13, r14);
OUTPUT_REGS(r15, rip, eflags);
#undef OUTPUT_REGS
}
void inst_info_break(void)
{
if (bps_cnt == 0) {
INFO("no breakpoints.\n");
return;
}
OUTPUT("%-6s\t%-12s\n", "Num", "Address");
for (int i = 0; i < bps_len; i++)
if (bps[i].addr)
OUTPUT("%-6d\t0x%lx\n", i, bps[i].addr);
}
void inst_break(void)
{
char *token = strtok(NULL, " \t\n");
if (token == NULL) {
ERROR("invalid command.\n");
INFO("Command: break [hex address]\n");
return;
}
uint64_t addr;
sscanf(token, "%lx", &addr);
bps_push(addr, poke(addr, 0xcc));
INFO("set a breakpoint at %p.\n", (void *)addr);
}
void inst_delete(void)
{
char *token = strtok(NULL, " \t\n");
if (token == NULL) {
ERROR("invalid command.\n");
INFO("Command: delete [id]\n");
return;
}
int id;
sscanf(token, "%d", &id);
if (bps_len <= id || bps[id].addr == 0x00)
INFO("breakpoint %d does not exist.\n", id);
else {
poke(bps[id].addr, bps[id].data);
bps[id].addr = 0x00, bps_cnt--;
INFO("delete breakpoint %d.\n", id);
}
}
void inst_patch(void)
{
char *token = strtok(NULL, " \t\n");
if (token == NULL) goto inst_patch_invalid;
uint64_t addr;
sscanf(token, "%lx", &addr);
token = strtok(NULL, " \t\n");
if (token == NULL) goto inst_patch_invalid;
uint64_t data;
sscanf(token, "%lx", &data);
token = strtok(NULL, " \t\n");
if (token == NULL) goto inst_patch_invalid;
int len;
sscanf(token, "%d", &len);
uint64_t val = ptrace(PTRACE_PEEKTEXT, child, addr, NULL);
DEBUG("original val = %lx\n", val);
uint64_t mask = ((uint64_t)1 << (len << 3)) - 1;
DEBUG("mask = %lx\n", mask);
val = (val & ~mask) | (data & mask);
DEBUG("modified val = %lx\n", val);
for (int i = 0; i < bps_len; i++)
if (bps[i].addr && addr <= bps[i].addr && bps[i].addr < addr + len) {
int j = bps[i].addr - addr;
bps[i].data = (data >> j) & 0xff;
}
if (ptrace(PTRACE_POKETEXT, child, addr, val) != 0) {
ERROR("inst_patch POKETEXT\n");
perror("inst_patch ptrace");
exit(1);
}
INFO("patch memory at address 0x%lx.\n", addr);
return;
inst_patch_invalid:
ERROR("invalid command.\n");
INFO("Command: patch [hex address] [hex value] [len]\n");
}
void inst_syscall(void)
{
if (!WIFSTOPPED(status)) {
ERROR("program not running.\n");
perror("inst_syscall");
disassemble_addr = 0x00;
return;
}
sync_regs();
uint64_t rip = regs.rip;
const struct bps_node *bp = find(rip);
if (bp) {
poke(bp->addr, bp->data);
ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
waitpid(child, &status, 0);
poke(bp->addr, 0xcc);
}
ptrace(PTRACE_SYSCALL, child, NULL, NULL);
waitpid(child, &status, 0);
if (!WIFSTOPPED(status)) {
INFO("the target program terminated.\n");
disassemble_addr = 0x00;
} else {
sync_regs();
rip = regs.rip;
DEBUG("rip = %p\n", (void *)rip);
if (WSTOPSIG(status) & 0x80) {
if (syscall_nr == 0xffff) {
syscall_nr = regs.orig_rax;
INFO("enter a syscall(%ld) at %p.\n",
syscall_nr, (void *)(rip - 2));
} else {
INFO("leave a syscall(%ld) = %llu at %p.\n",
syscall_nr, regs.rax, (void *)(rip - 2));
syscall_nr = 0xffff;
}
disassemble_addr = regs.rip - 2;
return;
}
bp = find(rip - 1);
if (bp == NULL) {
ERROR("inst_syscall bp = NULL\n");
perror("inst_syscall");
exit(1);
}
INFO("hit a breakpoint at %p.\n", (void *)(rip - 1));
poke(bp->addr, bp->data);
regs.rip -= 1;
ptrace(PTRACE_SETREGS, child, 0, &regs);
poke(bp->addr, 0xcc);
disassemble_addr = regs.rip;
}
}

52
sdb.h Normal file
View File

@@ -0,0 +1,52 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/user.h>
#define INSTRUCTION_COUNT 5
enum instruction {
INST_NOP = 0x00,
INST_EXIT = 0x01,
INST_LOAD = 0x02,
INST_SHOW = 0x10,
INST_INFO = 0x11,
INST_BREAK = 0x20,
INST_DELETE = 0x21,
INST_PATCH = 0x22,
INST_SI = 0x30,
INST_CONT = 0x31,
INST_SYSCALL = 0x32,
INST_INVALID = 0xff,
};
void sync_regs(void);
uint8_t poke(uint64_t addr, uint8_t data);
void run(const char *filename);
void disassemble();
void inst_load(char **filename);
void inst_si(void);
void inst_cont(void);
void inst_info(void);
void inst_info_reg(void);
void inst_info_break(void);
void inst_break(void);
void inst_delete(void);
void inst_patch(void);
void inst_syscall(void);
extern int child;
extern int status;
extern struct user_regs_struct regs;
extern uint64_t disassemble_addr;
extern long syscall_nr;

BIN
test.zip Normal file

Binary file not shown.

24
test/1.ans Normal file
View File

@@ -0,0 +1,24 @@
(sdb) si
** please load a program first.
(sdb) load ./hello
** program './hello' loaded. entry point 0x401000.
401000: f3 0f 1e fa endbr64
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
(sdb) si
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
(sdb) si
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
401017: bf 01 00 00 00 mov edi, 1
(sdb) cont
hello world!
** the target program terminated.

6
test/1.in Normal file
View File

@@ -0,0 +1,6 @@
./sdb
si
load ./hello
si
si
cont

44
test/2.ans Normal file
View File

@@ -0,0 +1,44 @@
** program './hello' loaded. entry point 0x401000.
401000: f3 0f 1e fa endbr64
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
(sdb) break 0x401005
** set a breakpoint at 0x401005.
(sdb) break 40102b
** set a breakpoint at 0x40102b.
(sdb) info break
Num Address
0 0x401005
1 0x40102b
(sdb) si
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
(sdb) si
** hit a breakpoint at 0x401005.
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
401017: bf 01 00 00 00 mov edi, 1
(sdb) cont
** hit a breakpoint at 0x40102b.
40102b: b8 01 00 00 00 mov eax, 1
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
(sdb) info reg
$rax 0x0000000000402000 $rbx 0x0000000000000000 $rcx 0x0000000000000000
$rdx 0x000000000000000e $rsi 0x0000000000402000 $rdi 0x0000000000000001
$rbp 0x00007ffe0e5cd5b8 $rsp 0x00007ffe0e5cd5b0 $r8 0x0000000000000000
$r9 0x0000000000000000 $r10 0x0000000000000000 $r11 0x0000000000000000
$r12 0x0000000000000000 $r13 0x0000000000000000 $r14 0x0000000000000000
$r15 0x0000000000000000 $rip 0x000000000040102b $eflags 0x0000000000000202
(sdb) cont
hello world!
** the target program terminated.

9
test/2.in Normal file
View File

@@ -0,0 +1,9 @@
./sdb ./hello
break 0x401005
break 40102b
info break
si
si
cont
info reg
cont

49
test/3.ans Normal file
View File

@@ -0,0 +1,49 @@
** program './guess' loaded. entry point 0x40108b.
40108b: f3 0f 1e fa endbr64
40108f: 55 push rbp
401090: 48 89 e5 mov rbp, rsp
401093: 48 83 ec 10 sub rsp, 0x10
401097: ba 12 00 00 00 mov edx, 0x12
(sdb) break 0x4010de
** set a breakpoint at 0x4010de.
(sdb) cont
guess a number > 1
** hit a breakpoint at 0x4010de.
4010de: 48 89 c7 mov rdi, rax
4010e1: e8 1a ff ff ff call 0x401000
4010e6: 85 c0 test eax, eax
4010e8: 75 1b jne 0x401105
4010ea: ba 06 00 00 00 mov edx, 6
(sdb) patch 0x4010e8 0x9090 2
** patch memory at address 0x4010e8.
(sdb) si
4010e1: e8 1a ff ff ff call 0x401000
4010e6: 85 c0 test eax, eax
4010e8: 90 nop
4010e9: 90 nop
4010ea: ba 06 00 00 00 mov edx, 6
(sdb) info break
Num Address
0 0x4010de
(sdb) delete 0
** delete breakpoint 0.
(sdb) break 0x4010ea
** set a breakpoint at 0x4010ea.
(sdb) delete 0
** breakpoint 0 does not exist.
(sdb) info break
Num Address
1 0x4010ea
(sdb) cont
** hit a breakpoint at 0x4010ea.
4010ea: ba 06 00 00 00 mov edx, 6
4010ef: 48 8d 05 1f 0f 00 00 lea rax, [rip + 0xf1f]
4010f6: 48 89 c6 mov rsi, rax
4010f9: bf 01 00 00 00 mov edi, 1
4010fe: e8 25 00 00 00 call 0x401128
(sdb) patch 0x402015 0x4e49570a 4
** patch memory at address 0x402015.
(sdb) cont
WIN
** the target program terminated.

14
test/3.in Normal file
View File

@@ -0,0 +1,14 @@
./sdb ./guess
break 0x4010de
cont
1
patch 0x4010e8 0x9090 2
si
info break
delete 0
break 0x4010ea
delete 0
info break
cont
patch 0x402015 0x4e49570a 4
cont

45
test/4.ans Normal file
View File

@@ -0,0 +1,45 @@
** program './hello' loaded. entry point 0x401000.
401000: f3 0f 1e fa endbr64
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
(sdb) break 0x401005
** set a breakpoint at 0x401005.
(sdb) break 40102b
** set a breakpoint at 0x40102b.
(sdb) cont
** hit a breakpoint at 0x401005.
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
401017: bf 01 00 00 00 mov edi, 1
(sdb) syscall
** hit a breakpoint at 0x40102b.
40102b: b8 01 00 00 00 mov eax, 1
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
(sdb) syscall
** enter a syscall(1) at 0x401030.
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
40103a: c3 ret
(sdb) syscall
hello world!
** leave a syscall(1) = 14 at 0x401030.
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
40103a: c3 ret
(sdb) syscall
** enter a syscall(60) at 0x401040.
401040: 0f 05 syscall
** the address is out of the range of the text section.
(sdb) syscall
** the target program terminated.

9
test/4.in Normal file
View File

@@ -0,0 +1,9 @@
./sdb ./hello
break 0x401005
break 40102b
cont
syscall
syscall
syscall
syscall
syscall

32
test/5.ans Normal file
View File

@@ -0,0 +1,32 @@
** program './guess' loaded. entry point 0x40108b.
40108b: f3 0f 1e fa endbr64
40108f: 55 push rbp
401090: 48 89 e5 mov rbp, rsp
401093: 48 83 ec 10 sub rsp, 0x10
401097: ba 12 00 00 00 mov edx, 0x12
(sdb) patch 0x4010e8 0x9090 2
** patch memory at address 0x4010e8.
(sdb) break 0x4010e8
** set a breakpoint at 0x4010e8.
(sdb) cont
guess a number > 1
** hit a breakpoint at 0x4010e8.
4010e8: 90 nop
4010e9: 90 nop
4010ea: ba 06 00 00 00 mov edx, 6
4010ef: 48 8d 05 1f 0f 00 00 lea rax, [rip + 0xf1f]
4010f6: 48 89 c6 mov rsi, rax
(sdb) break 4010ea
** set a breakpoint at 0x4010ea.
(sdb) patch 4010ea 0x03ba 4
** patch memory at address 0x4010ea.
(sdb) cont
** hit a breakpoint at 0x4010ea.
4010ea: ba 03 00 00 00 mov edx, 3
4010ef: 48 8d 05 1f 0f 00 00 lea rax, [rip + 0xf1f]
4010f6: 48 89 c6 mov rsi, rax
4010f9: bf 01 00 00 00 mov edi, 1
4010fe: e8 25 00 00 00 call 0x401128
(sdb) cont
ye** the target program terminated.

9
test/5.in Normal file
View File

@@ -0,0 +1,9 @@
./sdb ./guess
patch 0x4010e8 0x9090 2
break 0x4010e8
cont
1
break 4010ea
patch 4010ea 0x03ba 4
cont
cont

27
test/6.ans Normal file
View File

@@ -0,0 +1,27 @@
** program './guess' loaded. entry point 0x40108b.
40108b: f3 0f 1e fa endbr64
40108f: 55 push rbp
401090: 48 89 e5 mov rbp, rsp
401093: 48 83 ec 10 sub rsp, 0x10
401097: ba 12 00 00 00 mov edx, 0x12
(sdb) break 0x401128
** set a breakpoint at 0x401128.
(sdb) cont
** hit a breakpoint at 0x401128.
401128: b8 01 00 00 00 mov eax, 1
40112d: 0f 05 syscall
40112f: c3 ret
401130: b8 00 00 00 00 mov eax, 0
401135: 0f 05 syscall
(sdb) cont
guess a number > 1
** hit a breakpoint at 0x401128.
401128: b8 01 00 00 00 mov eax, 1
40112d: 0f 05 syscall
40112f: c3 ret
401130: b8 00 00 00 00 mov eax, 0
401135: 0f 05 syscall
(sdb) cont
no no no
** the target program terminated.

6
test/6.in Normal file
View File

@@ -0,0 +1,6 @@
./sdb ./guess
break 0x401128
cont
cont
1
cont

35
test/7.ans Normal file
View File

@@ -0,0 +1,35 @@
** program './hello' loaded. entry point 0x401000.
401000: f3 0f 1e fa endbr64
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
(sdb) break 0x401030
** set a breakpoint at 0x401030.
(sdb) break 0x401040
** set a breakpoint at 0x401040.
(sdb) syscall
** hit a breakpoint at 0x401030.
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
40103a: c3 ret
(sdb) syscall
** enter a syscall(1) at 0x401030.
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
40103a: c3 ret
(sdb) cont
hello world!
** hit a breakpoint at 0x401040.
401040: 0f 05 syscall
** the address is out of the range of the text section.
(sdb) syscall
** enter a syscall(60) at 0x401040.
401040: 0f 05 syscall
** the address is out of the range of the text section.
(sdb) syscall
** the target program terminated.

8
test/7.in Normal file
View File

@@ -0,0 +1,8 @@
./sdb ./hello
break 0x401030
break 0x401040
syscall
syscall
cont
syscall
syscall

8
test/Makefile Normal file
View File

@@ -0,0 +1,8 @@
all:
chmod +x run_examples.py guess hello
test: all
./run_examples.py
clean:
rm -f *.out diff.txt

BIN
test/guess Executable file

Binary file not shown.

BIN
test/hello Executable file

Binary file not shown.

134
test/run_examples.py Executable file
View File

@@ -0,0 +1,134 @@
#!/usr/bin/env python3
from typing import List
from pwn import process, context
context.log_level = "error"
cases_to_run = ["1", "2", "3", "4", "5", "6", "7"]
TIMEOUT_SECONDS = 0.01
def wrap_recvrepeat(r):
if r.poll() is not None:
return b""
return r.recvrepeat(TIMEOUT_SECONDS)
def recvrepeats(r):
output = wrap_recvrepeat(r)
while output == b"":
if r.poll() is not None:
break
output = wrap_recvrepeat(r)
ret = b""
while output != b"":
ret += output
output = wrap_recvrepeat(r)
return ret
def execute_process(
case: str, command: List[str], stdin: List[str]
) -> tuple[int, bytes]:
"""Returns the exit code and output of the process (including stdin and stderr)"""
print(f"Running case {case} with command: {command}")
try:
r = process(command, shell=False)
output = b""
for line in stdin:
ret = recvrepeats(r)
output += ret
output += line.encode("utf-8")
if r.poll() is None: # Only send if the process is still running
r.send(line.encode("utf-8"))
output += recvrepeats(r)
r.close()
except Exception as e:
print(f"Error: {e}")
return 1, b""
return 0, output
if __name__ == "__main__":
# Clean up the diff file
with open("diff.txt", "w") as f:
f.write("")
for case in cases_to_run:
with open(f"{case}.in", "r") as f:
lines = f.readlines()
run_command: List[str] = lines[0].split()
input = lines[1:]
_, output = execute_process(case, run_command, input)
# Remove the last prompt
if output.endswith(b"(sdb) "):
output = output[:-6]
# Remove null bytes
output = output.replace(b"\x00", b"")
# Write the output to a file
with open(f"{case}.out", "wb") as f:
f.write(output)
diff_command = f"diff -w -B -u {case}.out {case}.ans"
diff_process = process(diff_command, shell=True)
diff_output = diff_process.recvall()
diff_process.close()
diff_lines = diff_output.decode("utf-8").split("\n")
diff_lines = [
line for line in diff_lines if line.startswith("-") or line.startswith("+")
]
diff_lines = [line for line in diff_lines if not line.startswith("---")]
diff_lines = [line for line in diff_lines if not line.startswith("+++")]
i = 0
while True:
if i + 1 >= len(diff_lines):
break
if "-$rbp" in diff_lines[i] and "+$rbp" in diff_lines[i + 1]:
output_line = diff_lines.pop(i)[1:].split()
expected_line = diff_lines.pop(i)[1:].split()
if len(output_line) != 6:
diff_lines.append(f"error")
break
output_rbp = int(output_line[1], 16)
output_rsp = int(output_line[3], 16)
output_r8 = int(output_line[5], 16)
expected_rbp = int(expected_line[1], 16)
expected_rsp = int(expected_line[3], 16)
expected_r8 = int(expected_line[5], 16)
if (
output_rbp - output_rsp != expected_rbp - expected_rsp
or output_r8 != expected_r8
):
diff_lines.append(f"error")
break
continue
i += 1
# Print the diff output if there is a difference
print(f"Case {case}: {'PASS' if len(diff_lines) == 0 else 'FAIL'}", end="\n\n")
# Print the diff output to `diff.txt`
if len(diff_lines) > 0:
with open("diff.txt", "a") as f:
f.write(diff_output.decode("utf-8"))
f.write("\n\n")

13
test_case/Makefile Normal file
View File

@@ -0,0 +1,13 @@
.PHONY: all
all: ../sdb
python run.py 1
python run.py 2
python run.py 3
python run.py 4
python run.py h1
python run.py h2
python run.py h3
python run.py h4
python run.py h5
python run.py h6

BIN
test_case/deep Executable file

Binary file not shown.

BIN
test_case/game Executable file

Binary file not shown.

BIN
test_case/guess Executable file

Binary file not shown.

BIN
test_case/hello Executable file

Binary file not shown.

6
test_case/in/1.in Normal file
View File

@@ -0,0 +1,6 @@
../sdb
si
load ./hello
si
si
cont

9
test_case/in/2.in Normal file
View File

@@ -0,0 +1,9 @@
../sdb ./hello
break 0x401005
break 40102b
info break
si
si
cont
info reg
cont

14
test_case/in/3.in Normal file
View File

@@ -0,0 +1,14 @@
../sdb ./guess
break 0x4010de
cont
1
patch 0x4010e8 0x9090 2
si
info break
delete 0
break 0x4010ea
delete 0
info break
cont
patch 0x402015 0x4e49570a 4
cont

9
test_case/in/4.in Normal file
View File

@@ -0,0 +1,9 @@
../sdb ./hello
break 0x401005
break 40102b
cont
syscall
syscall
syscall
syscall
syscall

13
test_case/in/h1.in Normal file
View File

@@ -0,0 +1,13 @@
../sdb ./game
break 401005
break 401009
info break
syscall
syscall
delete 0
cont
2
break 401005
info break
cont
2

9
test_case/in/h2.in Normal file
View File

@@ -0,0 +1,9 @@
../sdb ./game
break 401005
cont
patch 40101a 0x02f88348 4
cont
1
patch 40101a 0x01f88348 4
cont
1

6
test_case/in/h3.in Normal file
View File

@@ -0,0 +1,6 @@
../sdb
si
load ./deep
si
si
cont

9
test_case/in/h4.in Normal file
View File

@@ -0,0 +1,9 @@
../sdb ./deep
break 401136
break 40113d
info break
si
si
cont
info reg
cont

12
test_case/in/h5.in Normal file
View File

@@ -0,0 +1,12 @@
../sdb ./deep
break 40109c
info break
break 401031
info break
delete 0
info break
delete 3
info break
cont
info break
cont

9
test_case/in/h6.in Normal file
View File

@@ -0,0 +1,9 @@
../sdb ./game
break 0x4010f1
syscall
syscall
syscall
syscall
3
syscall
syscall

19
test_case/out/1.ans Normal file
View File

@@ -0,0 +1,19 @@
** please load a program first.
** program './hello' loaded. entry point 0x401000.
401000: f3 0f 1e fa endbr64
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
401017: bf 01 00 00 00 mov edi, 1
hello world!
** the target program terminated.

36
test_case/out/2.ans Normal file
View File

@@ -0,0 +1,36 @@
** program './hello' loaded. entry point 0x401000.
401000: f3 0f 1e fa endbr64
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
** set a breakpoint at 0x401005.
** set a breakpoint at 0x40102b.
Num Address
0 0x401005
1 0x40102b
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
** hit a breakpoint at 0x401005.
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
401017: bf 01 00 00 00 mov edi, 1
** hit a breakpoint at 0x40102b.
40102b: b8 01 00 00 00 mov eax, 1
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
$rax 0x0000000000402000 $rbx 0x0000000000000000 $rcx 0x0000000000000000
$rdx 0x000000000000000e $rsi 0x0000000000402000 $rdi 0x0000000000000001
$rbp 0x00007ffe0e5cd5b8 $rsp 0x00007ffe0e5cd5b0 $r8 0x0000000000000000
$r9 0x0000000000000000 $r10 0x0000000000000000 $r11 0x0000000000000000
$r12 0x0000000000000000 $r13 0x0000000000000000 $r14 0x0000000000000000
$r15 0x0000000000000000 $rip 0x000000000040102b $eflags 0x0000000000000202
hello world!
** the target program terminated.

37
test_case/out/3.ans Normal file
View File

@@ -0,0 +1,37 @@
** program './guess' loaded. entry point 0x40108b.
40108b: f3 0f 1e fa endbr64
40108f: 55 push rbp
401090: 48 89 e5 mov rbp, rsp
401093: 48 83 ec 10 sub rsp, 0x10
401097: ba 12 00 00 00 mov edx, 0x12
** set a breakpoint at 0x4010de.
guess a number >
** hit a breakpoint at 0x4010de.
4010de: 48 89 c7 mov rdi, rax
4010e1: e8 1a ff ff ff call 0x401000
4010e6: 85 c0 test eax, eax
4010e8: 75 1b jne 0x401105
4010ea: ba 06 00 00 00 mov edx, 6
** patch memory at address 0x4010e8.
4010e1: e8 1a ff ff ff call 0x401000
4010e6: 85 c0 test eax, eax
4010e8: 90 nop
4010e9: 90 nop
4010ea: ba 06 00 00 00 mov edx, 6
Num Address
0 0x4010de
** delete breakpoint 0.
** set a breakpoint at 0x4010ea.
** breakpoint 0 does not exist.
Num Address
1 0x4010ea
** hit a breakpoint at 0x4010ea.
4010ea: ba 06 00 00 00 mov edx, 6
4010ef: 48 8d 05 1f 0f 00 00 lea rax, [rip + 0xf1f]
4010f6: 48 89 c6 mov rsi, rax
4010f9: bf 01 00 00 00 mov edi, 1
4010fe: e8 25 00 00 00 call 0x401128
** patch memory at address 0x402015.
WIN
** the target program terminated.

37
test_case/out/4.ans Normal file
View File

@@ -0,0 +1,37 @@
** program './hello' loaded. entry point 0x401000.
401000: f3 0f 1e fa endbr64
401004: 55 push rbp
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
** set a breakpoint at 0x401005.
** set a breakpoint at 0x40102b.
** hit a breakpoint at 0x401005.
401005: 48 89 e5 mov rbp, rsp
401008: ba 0e 00 00 00 mov edx, 0xe
40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
401014: 48 89 c6 mov rsi, rax
401017: bf 01 00 00 00 mov edi, 1
** hit a breakpoint at 0x40102b.
40102b: b8 01 00 00 00 mov eax, 1
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
** enter a syscall(1) at 0x401030.
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
40103a: c3 ret
hello world!
** leave a syscall(1) = 14 at 0x401030.
401030: 0f 05 syscall
401032: c3 ret
401033: b8 00 00 00 00 mov eax, 0
401038: 0f 05 syscall
40103a: c3 ret
** enter a syscall(60) at 0x401040.
401040: 0f 05 syscall
** the address is out of the range of the text section.
** the target program terminated.

44
test_case/out/h1.ans Normal file
View File

@@ -0,0 +1,44 @@
** program './game' loaded. entry point 0x401000.
401000: b9 05 00 00 00 mov ecx, 5
401005: 48 83 f9 00 cmp rcx, 0
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
** set a breakpoint at 0x401005.
** set a breakpoint at 0x401009.
Num Address
0 0x401005
1 0x401009
** hit a breakpoint at 0x401005.
401005: 48 83 f9 00 cmp rcx, 0
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
401015: e8 72 00 00 00 call 0x40108c
** hit a breakpoint at 0x401009.
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
401015: e8 72 00 00 00 call 0x40108c
40101a: 48 83 f8 01 cmp rax, 1
** delete breakpoint 0.
guess a number :
wrong
** hit a breakpoint at 0x401009.
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
401015: e8 72 00 00 00 call 0x40108c
40101a: 48 83 f8 01 cmp rax, 1
** set a breakpoint at 0x401005.
Num Address
1 0x401009
2 0x401005
guess a number :
wrong
** hit a breakpoint at 0x401005.
401005: 48 83 f9 00 cmp rcx, 0
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
401015: e8 72 00 00 00 call 0x40108c

26
test_case/out/h2.ans Normal file
View File

@@ -0,0 +1,26 @@
** program './game' loaded. entry point 0x401000.
401000: b9 05 00 00 00 mov ecx, 5
401005: 48 83 f9 00 cmp rcx, 0
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
** set a breakpoint at 0x401005.
** hit a breakpoint at 0x401005.
401005: 48 83 f9 00 cmp rcx, 0
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
401015: e8 72 00 00 00 call 0x40108c
** patch memory at address 0x40101a.
guess a number :
wrong
** hit a breakpoint at 0x401005.
401005: 48 83 f9 00 cmp rcx, 0
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
401015: e8 72 00 00 00 call 0x40108c
** patch memory at address 0x40101a.
guess a number :
you win
** the target program terminated.

21
test_case/out/h3.ans Normal file
View File

@@ -0,0 +1,21 @@
** please load a program first.
** program './deep' loaded. entry point 0x401131.
401131: f3 0f 1e fa endbr64
401135: 55 push rbp
401136: 48 89 e5 mov rbp, rsp
401139: 48 83 ec 10 sub rsp, 0x10
40113d: b8 00 00 00 00 mov eax, 0
401135: 55 push rbp
401136: 48 89 e5 mov rbp, rsp
401139: 48 83 ec 10 sub rsp, 0x10
40113d: b8 00 00 00 00 mov eax, 0
401142: e8 3f ff ff ff call 0x401086
401136: 48 89 e5 mov rbp, rsp
401139: 48 83 ec 10 sub rsp, 0x10
40113d: b8 00 00 00 00 mov eax, 0
401142: e8 3f ff ff ff call 0x401086
401147: 89 45 fc mov dword ptr [rbp - 4], eax
this is callee
hello world
hello unix
** the target program terminated.

38
test_case/out/h4.ans Normal file
View File

@@ -0,0 +1,38 @@
** program './deep' loaded. entry point 0x401131.
401131: f3 0f 1e fa endbr64
401135: 55 push rbp
401136: 48 89 e5 mov rbp, rsp
401139: 48 83 ec 10 sub rsp, 0x10
40113d: b8 00 00 00 00 mov eax, 0
** set a breakpoint at 0x401136.
** set a breakpoint at 0x40113d.
Num Address
0 0x401136
1 0x40113d
401135: 55 push rbp
401136: 48 89 e5 mov rbp, rsp
401139: 48 83 ec 10 sub rsp, 0x10
40113d: b8 00 00 00 00 mov eax, 0
401142: e8 3f ff ff ff call 0x401086
** hit a breakpoint at 0x401136.
401136: 48 89 e5 mov rbp, rsp
401139: 48 83 ec 10 sub rsp, 0x10
40113d: b8 00 00 00 00 mov eax, 0
401142: e8 3f ff ff ff call 0x401086
401147: 89 45 fc mov dword ptr [rbp - 4], eax
** hit a breakpoint at 0x40113d.
40113d: b8 00 00 00 00 mov eax, 0
401142: e8 3f ff ff ff call 0x401086
401147: 89 45 fc mov dword ptr [rbp - 4], eax
40114a: b8 00 00 00 00 mov eax, 0
40114f: e8 5d ff ff ff call 0x4010b1
$rax 0x0000000000000000 $rbx 0x0000000000000000 $rcx 0x0000000000000000
$rdx 0x0000000000000000 $rsi 0x0000000000000000 $rdi 0x0000000000000000
$rbp 0x00007fffffffe0a8 $rsp 0x00007fffffffe098 $r8 0x0000000000000000
$r9 0x0000000000000000 $r10 0x0000000000000000 $r11 0x0000000000000000
$r12 0x0000000000000000 $r13 0x0000000000000000 $r14 0x0000000000000000
$r15 0x0000000000000000 $rip 0x000000000040113d $eflags 0x0000000000000202
this is callee
hello world
hello unix
** the target program terminated.

31
test_case/out/h5.ans Normal file
View File

@@ -0,0 +1,31 @@
** program './deep' loaded. entry point 0x401131.
401131: f3 0f 1e fa endbr64
401135: 55 push rbp
401136: 48 89 e5 mov rbp, rsp
401139: 48 83 ec 10 sub rsp, 0x10
40113d: b8 00 00 00 00 mov eax, 0
** set a breakpoint at 0x40109c.
Num Address
0 0x40109c
** set a breakpoint at 0x401031.
Num Address
0 0x40109c
1 0x401031
** delete breakpoint 0.
Num Address
1 0x401031
** breakpoint 3 does not exist.
Num Address
1 0x401031
** hit a breakpoint at 0x401031.
401031: 48 89 c6 mov rsi, rax
401034: bf 01 00 00 00 mov edi, 1
401039: e8 20 01 00 00 call 0x40115e
40103e: 90 nop
40103f: c9 leave
Num Address
1 0x401031
this is callee
hello world
hello unix
** the target program terminated.

44
test_case/out/h6.ans Normal file
View File

@@ -0,0 +1,44 @@
** program './game' loaded. entry point 0x401000.
401000: b9 05 00 00 00 mov ecx, 5
401005: 48 83 f9 00 cmp rcx, 0
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
** set a breakpoint at 0x4010f1.
** enter a syscall(1) at 0x401052.
401052: 0f 05 syscall
401054: 59 pop rcx
401055: c3 ret
401056: 51 push rcx
401057: b8 01 00 00 00 mov eax, 1
guess a number :
** leave a syscall(1) = 18 at 0x401052.
401052: 0f 05 syscall
401054: 59 pop rcx
401055: c3 ret
401056: 51 push rcx
401057: b8 01 00 00 00 mov eax, 1
** enter a syscall(0) at 0x401088.
401088: 0f 05 syscall
40108a: 59 pop rcx
40108b: c3 ret
40108c: 51 push rcx
40108d: b8 00 00 00 00 mov eax, 0
** leave a syscall(0) = 2 at 0x401088.
401088: 0f 05 syscall
40108a: 59 pop rcx
40108b: c3 ret
40108c: 51 push rcx
40108d: b8 00 00 00 00 mov eax, 0
** hit a breakpoint at 0x4010f1.
4010f1: 48 8d 35 2b 0f 00 00 lea rsi, [rip + 0xf2b]
4010f8: ba 06 00 00 00 mov edx, 6
4010fd: 0f 05 syscall
4010ff: 59 pop rcx
401100: c3 ret
** enter a syscall(1) at 0x4010fd.
4010fd: 0f 05 syscall
4010ff: 59 pop rcx
401100: c3 ret
401101: b8 3c 00 00 00 mov eax, 0x3c
401106: 48 31 ff xor rdi, rdi

44
test_case/output.txt Normal file
View File

@@ -0,0 +1,44 @@
** program './game' loaded. entry point 0x401000.
401000: b9 05 00 00 00 mov ecx, 5
401005: 48 83 f9 00 cmp rcx, 0
401009: 74 1f je 0x40102a
40100b: e8 2b 00 00 00 call 0x40103b
401010: e8 5c 00 00 00 call 0x401071
** set a breakpoint at 0x4010f1.
** enter a syscall(1) at 0x401052.
401052: 0f 05 syscall
401054: 59 pop rcx
401055: c3 ret
401056: 51 push rcx
401057: b8 01 00 00 00 mov eax, 1
guess a number :
** leave a syscall(1) = 18 at 0x401052.
401052: 0f 05 syscall
401054: 59 pop rcx
401055: c3 ret
401056: 51 push rcx
401057: b8 01 00 00 00 mov eax, 1
** enter a syscall(0) at 0x401088.
401088: 0f 05 syscall
40108a: 59 pop rcx
40108b: c3 ret
40108c: 51 push rcx
40108d: b8 00 00 00 00 mov eax, 0
** leave a syscall(0) = 2 at 0x401088.
401088: 0f 05 syscall
40108a: 59 pop rcx
40108b: c3 ret
40108c: 51 push rcx
40108d: b8 00 00 00 00 mov eax, 0
** hit a breakpoint at 0x4010f1.
4010f1: 48 8d 35 2b 0f 00 00 lea rsi, [rip + 0xf2b]
4010f8: ba 06 00 00 00 mov edx, 6
4010fd: 0f 05 syscall
4010ff: 59 pop rcx
401100: c3 ret
** enter a syscall(1) at 0x4010fd.
4010fd: 0f 05 syscall
4010ff: 59 pop rcx
401100: c3 ret
401101: b8 3c 00 00 00 mov eax, 0x3c
401106: 48 31 ff xor rdi, rdi

71
test_case/run.py Normal file
View File

@@ -0,0 +1,71 @@
from pwn import *
import time
import sys
import difflib
def read_file(filename):
"""Read a file and return its contents as a list of lines."""
with open(filename, "r") as f:
return f.readlines()
def normalize_line(line):
"""Normalize a line by stripping leading/trailing whitespace and reducing internal whitespace to a single space."""
return ' '.join(line.split())
def compare_files(file1, file2):
"""Compare two files and print the differences or 'accept' if they are the same."""
content1 = read_file(file1)
content2 = read_file(file2)
# Normalize lines to ignore whitespace differences
normalized1 = [normalize_line(line) for line in content1]
normalized2 = [normalize_line(line) for line in content2]
diff = difflib.unified_diff(normalized1, normalized2, fromfile=file1, tofile=file2)
# Convert the generator to a list to check if there are any differences
diff_list = list(diff)
if not diff_list:
print("accept")
else:
for line in diff_list:
print(line)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: ./run.py <test case id>")
sys.exit(1)
filename = "./in/" + sys.argv[1] + ".in"
f = open(filename)
input_lines = f.read().splitlines()
# start process
p_run = input_lines[0].split(" ")
if len(p_run) == 1:
p = process([p_run[0]])
else:
p = process([p_run[0]] + [p_run[1]])
for i in range(1, len(input_lines)):
# info(input_lines[i])
p.sendline(input_lines[i].encode())
time.sleep(0.2)
# wait
time.sleep(1)
# \x00, (sdb)...
with open("output.txt", "w", encoding="utf-8") as f:
output = p.recvall(timeout=1).decode("utf-8")
output = output.replace("\x00", "") # \x00 terminate
output = output.replace("(sdb) ", "")
output = output.replace("guess a number > ", "guess a number > \n")
f.write(output)
p.close()
ans_file = "./out/" + sys.argv[1] + ".ans"
info(ans_file)
compare_files("output.txt", ans_file)

7
tmp Normal file
View File

@@ -0,0 +1,7 @@
** program 'test/hello' loaded. entry point 0x401000
 401000: f3 0f 1e fa endbr64
 401004: 55 push rbp
 401005: 48 89 e5 mov rbp, rsp
 401008: ba 0e 00 00 00 mov edx, 0xe
 40100d: 48 8d 05 ec 0f 00 00 lea rax, [rip + 0xfec]
(sdb) 

27
vector.c Normal file
View File

@@ -0,0 +1,27 @@
#include "vector.h"
#include <stdlib.h>
struct bps_node *bps = NULL;
int bps_len = 0, bps_cnt = 0, bps_max = 0;
const struct bps_node *find(uint64_t addr)
{
for (int i = 0; i < bps_len; i++)
if (bps[i].addr && bps[i].addr == addr)
return &bps[i];
return NULL;
}
int bps_push(uint64_t addr, uint8_t data)
{
if (bps_max == 0)
bps = malloc((bps_max = 1) * sizeof(struct bps_node));
if (bps_len + 1 >= bps_max)
bps = realloc(bps, (bps_max <<= 1) * sizeof(struct bps_node));
bps[bps_len].addr = addr;
bps[bps_len].data = data;
bps_cnt++;
return bps_len++;
}

14
vector.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <stdint.h>
struct bps_node {
uint64_t addr;
uint8_t data;
};
const struct bps_node *find(uint64_t addr);
int bps_push(uint64_t addr, uint8_t data);
extern struct bps_node *bps;
extern int bps_len, bps_cnt, bps_max;