Commit b9495f69 by yinqidi

update the emulation scripts

parent 5c6a67f0
binwalk @ f57a746c
Subproject commit f57a746cf1933a44cf0b0ececdb905f7dd7afeaa
[DEFAULT]
sudo_password=yinqidi
firmadyne_path=/home/yinqidi/Desktop/EmuFuzz/Emulation
sudo_password=hunter
firmadyne_path=/home/hunter/Desktop/IOT-fuzz/Emulation
#! /usr/bin/python
#! /usr/bin/python3
import os
import os.path
......
#include<stdio.h>
int main()
{
FILE *fp=fopen("/ci/ci_file", "r");
if (fp)
{
char buff[255];
fgets(buff, 255, (FILE*)fp);
printf("%s\n", buff);
}
else
printf("Read Error\n");
fclose(fp);
return 0;
}
[mips]
name = 2.6.39.4+|#1 Fri Dec 11 20:11:00 PST 2020|mips
version.a = 2
version.b = 6
version.c = 39
#arch = mips
task.per_cpu_offsets_addr = 0
task.per_cpu_offset_0_addr = 0
task.current_task_addr = 2154662400
task.init_addr = 2154662400
#task.per_cpu_offsets_addr = 0
#task.per_cpu_offset_0_addr = 0x0
#task.current_task_addr = 0x806d8a00
#task.init_addr = 0x806d8a00
task.size = 1112
task.tasks_offset = 156
task.pid_offset = 196
task.tgid_offset = 200
task.group_leader_offset = 228
task.thread_group_offset = 284
task.real_parent_offset = 204
task.parent_offset = 208
task.mm_offset = 164
task.stack_offset = 4
task.real_cred_offset = 408
task.cred_offset = 412
task.comm_offset = 420
task.comm_size = 16
task.files_offset = 852
task.start_time_offset = 340
cred.uid_offset = 4
cred.gid_offset = 8
cred.euid_offset = 20
cred.egid_offset = 24
mm.size = 380
mm.mmap_offset = 0
mm.pgd_offset = 36
mm.arg_start_offset = 140
mm.start_brk_offset = 128
mm.brk_offset = 132
mm.start_stack_offset = 136
vma.size = 88
vma.vm_mm_offset = 0
vma.vm_start_offset = 4
vma.vm_end_offset = 8
vma.vm_next_offset = 12
vma.vm_flags_offset = 24
vma.vm_file_offset = 76
fs.f_path_dentry_offset = 12
fs.f_path_mnt_offset = 8
fs.f_pos_offset = 32
fs.fdt_offset = 4
fs.fdtab_offset = 8
fs.fd_offset = 4
qstr.size = 12
qstr.name_offset = 8
path.d_name_offset = 20
path.d_iname_offset = 36
path.d_parent_offset = 16
path.d_op_offset = 80
path.d_dname_offset = 24
path.mnt_root_offset = 16
path.mnt_parent_offset = 8
path.mnt_mountpoint_offset = 12
......@@ -3,7 +3,7 @@
ROOT_DIR="$HOME"
HOME_DIR="$ROOT_DIR/Desktop/EmuFuzz/Emulation"
HOME_DIR="$ROOT_DIR/Desktop/IOT-fuzz/Emulation"
export EMU_DIR=$HOME_DIR
......@@ -18,3 +18,15 @@ export LIB_DIR="$HOME_DIR/source/LIB"
export SCRIPT_DIR="$HOME_DIR/scripts"
export TARBALL_DIR="$HOME_DIR/images"
add_partition(){
kpartx_out="$(kpartx -a -s -v "${1}")"
DEVICE="$(echo $kpartx_out | cut -d ' ' -f 3)"
DEVICE="/dev/mapper/$DEVICE"
echo $DEVICE
}
del_partition () {
kpartx -d ${1}
}
......@@ -77,7 +77,7 @@ do
# ARCHEND=${ARCH}${END}
# echo ${ARCHEND}
# #psql -d firmware -U firmadyne -h 127.0.0.1 -q -c "UPDATE image SET arch = '$ARCHEND' WHERE id = $IID;"
# ####psql -d firmware -U firmadyne -h 127.0.0.1 -q -c "UPDATE image SET arch = '$ARCHEND' WHERE id = $IID;"
# rm -fr "/tmp/${IID}"
# exit 0
......
......@@ -11,9 +11,9 @@ ARCH=${2}
WORK_DIR="${WORK_DIR}/${IID}"
cd ${WORK_DIR}
qemu-img convert -f raw -O qcow2 image.raw image.qcow2
cd -
# cd ${WORK_DIR}
# qemu-img convert -f raw -O qcow2 image.raw image.qcow2
# cd -
if [ "$ARCH" == "mipseb" ]; then
cp "${KERNEL_DIR}/${ARCH}/vmlinux" "${WORK_DIR}/vmlinux"
chmod a+x "${WORK_DIR}/vmlinux"
......
# Kernel Information Module via gdb
First. Go read the normal kernelinfo [readme](https://github.com/panda-re/panda/blob/master/panda/plugins/osi_linux/utils/kernelinfo/README.md).
## Requirements
- GDB 8 or above. This is needed for the GDB API to support `gdb.execute(to_string=True)`.
- Python 3.6 or above. This is to support fstrings.
- A kernel vmlinux file for linux 3.0.0 or later that is *not stripped and has debug symbols*.
## Where does this apply?
Kernels with debug symbols. Likely one that you built. If it's stripped go back to the other method.
Example: `vmlinux: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, BuildID[sha1]=181ca40a44bef701cf0559b185180053a152029d, with debug_info, not stripped`
## How does this work?
This crux of this is python script run inside of gdb to gather DWARF symbols.
That script creates a command `kernel_info` which runs a bunch of GDB commands to gather information from the DWARF symbols and output it.
## How do I use it?
Run `run.sh` with a vmlinux and an output file.
`./run.sh vmlinux file.out`
Alternatively,
- start up gdb on the `vmlinux` file: `gdb ./vmlinux`
- load our python script: `source extract_kernelinfo.py`
- run our python script: `kernel_info output.file`
- quit: `q`
import gdb
import sys
import re
file_out = sys.stdout
def print_size(structv, cfgmemb, cfgname):
size = gdb.execute(f'printf "%u",(size_t) sizeof({structv})',to_string=True)
print(f"{cfgname}.{cfgmemb} = {size}",file=file_out)
def print_offset(structp, memb, cfgname):
offset = gdb.execute(f'printf "%d",(int)&(({structp}*)0)->{memb}',to_string=True)
print(f"{cfgname}.{memb}_offset = {offset}",file=file_out)
def print_offset_from_member(structp, memb_base, memb_dest, cfgname):
offset = gdb.execute(f'printf "%lld", (int64_t)&(({structp})*0)->{memb_dest} - (int64_t)&(({structp})*0)->{memb_base}',to_string=True)
print(f"{cfgname}.{memb_dest}_offset = {offset}",file=file_out)
def get_symbol_as_string(name):
return gdb.execute(f'printf "%s",{name}',to_string=True)
class KernelInfo(gdb.Command):
def __init__(self):
super(KernelInfo, self).__init__("kernel_info", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
global file_out
if arg:
file_out = open(arg, "w+")
print(f"Printing output to {arg}")
print(f"[kernelinfo]",file=file_out)
uts_release = get_symbol_as_string("init_uts_ns->name->release")
uts_version = get_symbol_as_string("init_uts_ns->name->version")
uts_machine = get_symbol_as_string("init_uts_ns->name->machine")
print(f"name = {uts_release}|{uts_version}|{uts_machine}",file=file_out)
release = get_symbol_as_string("init_uts_ns->name->release")
versions = release.split(".")
# version.c can have a bunch of junk - just extract a number
versions[2] = re.search("\d+",versions[2]).group(0)
print(f"version.a = {versions[0]}",file=file_out)
print(f"version.b = {versions[1]}",file=file_out)
print(f"version.c = {versions[2]}",file=file_out)
# TODO: we should use this to generate the file. See issue 651
print(f"#arch = {uts_machine}", file=file_out)
try:
per_cpu_offset_addr = gdb.execute('printf "%llu", &__per_cpu_offset',to_string=True)
per_cpu_offset_0_addr = gdb.execute('printf "%llu", __per_cpu_offset[0]',to_string=True)
except:
# This should be an arch-specific requirement, arm/mips don't have it (#651)
assert("x86" not in uts_machine), "Failed to find __per_cpu_offset_data"
per_cpu_offset_addr = 0
per_cpu_offset_0_addr = 0
print(f"task.per_cpu_offsets_addr = {per_cpu_offset_addr}",file=file_out)
print(f"task.per_cpu_offset_0_addr = {per_cpu_offset_0_addr}",file=file_out)
init_task_addr = gdb.execute('printf "%llu", &init_task',to_string=True)
# current_task is only an x86 thing
# It's defined in /arch/x86/kernel/cpu/common.c
if "x86" in uts_machine:
current_task_addr = gdb.execute('printf "%llu", &current_task',to_string=True)
else:
current_task_addr = init_task_addr
print(f"task.current_task_addr = {current_task_addr}",file=file_out)
print(f"task.init_addr = {init_task_addr}",file=file_out)
print(f"#task.per_cpu_offsets_addr = {hex(int(per_cpu_offset_addr))[2:]}",file=file_out)
print(f"#task.per_cpu_offset_0_addr = {hex(int(per_cpu_offset_0_addr))}",file=file_out)
print(f"#task.current_task_addr = {hex(int(current_task_addr))}",file=file_out)
print(f"#task.init_addr = {hex(int(init_task_addr))}",file=file_out)
print_size("struct task_struct", "size", "task");
print_offset("struct task_struct", "tasks", "task");
print_offset("struct task_struct", "pid", "task");
print_offset("struct task_struct", "tgid", "task");
print_offset("struct task_struct", "group_leader", "task");
print_offset("struct task_struct", "thread_group", "task");
print_offset("struct task_struct", "real_parent", "task");
print_offset("struct task_struct", "parent", "task");
print_offset("struct task_struct", "mm", "task");
print_offset("struct task_struct", "stack", "task");
print_offset("struct task_struct", "real_cred", "task");
print_offset("struct task_struct", "cred", "task");
print_offset("struct task_struct", "comm", "task");
print_size("((struct task_struct*)0)->comm", "comm_size", "task");
print_offset("struct task_struct", "files", "task");
print_offset("struct task_struct", "start_time", "task");
print_offset("struct cred", "uid", "cred");
print_offset("struct cred", "gid", "cred");
print_offset("struct cred", "euid", "cred");
print_offset("struct cred", "egid", "cred");
print_size("struct mm_struct", "size", "mm");
print_offset("struct mm_struct", "mmap", "mm");
print_offset("struct mm_struct", "pgd", "mm");
print_offset("struct mm_struct", "arg_start", "mm");
print_offset("struct mm_struct", "start_brk", "mm");
print_offset("struct mm_struct", "brk", "mm");
print_offset("struct mm_struct", "start_stack", "mm");
print_size("struct vm_area_struct", "size", "vma");
print_offset("struct vm_area_struct", "vm_mm", "vma");
print_offset("struct vm_area_struct", "vm_start", "vma");
print_offset("struct vm_area_struct", "vm_end", "vma");
print_offset("struct vm_area_struct", "vm_next", "vma");
print_offset("struct vm_area_struct", "vm_flags", "vma");
print_offset("struct vm_area_struct", "vm_file", "vma");
# used in reading file information
# This is gross because the name doesn't match the symbol identifier.
fstruct = "struct file"
f_path_offset = gdb.execute(f'printf "%d",(int)&(({fstruct}*)0)->f_path.dentry',to_string=True)
print(f"fs.f_path_dentry_offset = {f_path_offset}",file=file_out)
offset = gdb.execute(f'printf "%d",(int)&(({fstruct}*)0)->f_path.mnt',to_string=True)
print(f"fs.f_path_mnt_offset = {offset}",file=file_out)
print_offset("struct file", "f_pos", "fs");
print_offset("struct files_struct", "fdt", "fs");
print_offset("struct files_struct", "fdtab", "fs");
print_offset("struct fdtable", "fd", "fs");
# used for resolving path names */
print_size("struct qstr", "size", "qstr");
print_offset("struct qstr", "name", "qstr");
print_offset("struct dentry", "d_name", "path");
print_offset("struct dentry", "d_iname", "path");
print_offset("struct dentry", "d_parent", "path");
print_offset("struct dentry", "d_op", "path");
print_offset("struct dentry_operations", "d_dname", "path");
print_offset("struct vfsmount", "mnt_root", "path");
if int(versions[0]) >= 3:
# fields in struct mount
print_offset_from_member("struct mount", "mnt", "mnt_parent", "path");
print_offset_from_member("struct mount", "mnt", "mnt_mountpoint", "path");
else:
# fields in struct vfsmount
print_offset("struct vfsmount", "mnt_parent", "path");
print_offset("struct vfsmount", "mnt_mountpoint", "path");
if file_out != sys.stdout:
file_out.close()
# This registers our class to the gdb runtime at "source" time.
KernelInfo()
#!/bin/bash
if [ "$#" -lt 1 ]; then
echo "run.sh [debuggable vmlinux file] [output file]"
exit
fi
VMLINUX=$1
OUTPUT_FILE=$2
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
gdb $VMLINUX -ex "source ${SCRIPTDIR}/extract_kernelinfo.py" -ex "kernel_info $OUTPUT_FILE" -ex "q"
......@@ -40,9 +40,7 @@ echo "----Creating Partition Table----"
echo -e "o\nn\np\n1\n\n\nw" | /sbin/fdisk "${IMAGE}"
echo "----Mounting QEMU Image----"
kpartx_out="$(kpartx -a -s -v "${IMAGE}")"
DEVICE="$(echo $kpartx_out | cut -d ' ' -f 3)"
DEVICE="/dev/mapper/$DEVICE"
DEVICE=`add_partition ${IMAGE}`
echo $DEVICE
sleep 1
......@@ -68,6 +66,10 @@ mkdir "${IMAGE_DIR}/firmadyne/"
mkdir "${IMAGE_DIR}/firmadyne/libnvram/"
mkdir "${IMAGE_DIR}/firmadyne/libnvram.override/"
echo "----Adding CI files----"
cp "${SCRIPT_DIR}/test_${ARCH}" "${IMAGE_DIR}/test"
cp "${SCRIPT_DIR}/ci_file" "${IMAGE_DIR}/"
echo "----Patching Filesystem (chroot)----"
cp $(which busybox) "${IMAGE_DIR}"
cp "${SCRIPT_DIR}/fixImage.sh" "${IMAGE_DIR}"
......@@ -94,5 +96,5 @@ chmod a+x "${IMAGE_DIR}/firmadyne/preInit.sh"
echo "----Unmounting QEMU Image----"
sync
umount "${DEVICE}"
kpartx -d "${IMAGE}"
del_partition ${IMAGE}
......@@ -29,7 +29,7 @@ trap cleanup EXIT
echo "Starting firmware emulation... use Ctrl-a + x to exit"
sleep 1s
%(QEMU_ENV_VARS)s %(QEMU)s -m 256 -M %(MACHINE)s -kernel ./vmlinux \\
%(QEMU_ENV_VARS)s %(QEMU)s -m 256 -M %(MACHINE)s -kernel %(KERNEL)s \\
%(QEMU_DISK)s -append "root=%(QEMU_ROOTFS)s console=ttyS0 nandsim.parts=64,64,64,64,64,64,64,64,64,64 rdinit=/firmadyne/preInit.sh rw debug ignore_loglevel print-fatal-signals=1 user_debug=31 firmadyne.syscall=0" \\
-nographic \\
%(QEMU_NETWORK)s | tee qemu.final.serial.log
......@@ -261,13 +261,15 @@ def qemuCmd(iid, network, arch, endianness):
qemu = "qemu-system-mips"
qemu_rootfs = "/dev/sda1"
qemuKernel = "./vmlinux"
qemuDisk = "-drive if=ide,format=qcow2,file=image.qcow2"
# qemuDisk = "-drive if=ide,format=qcow2,file=image.qcow2"
qemuDisk = "-drive if=ide,format=raw,file=image.raw"
if endianness != "eb" and endianness != "el":
raise Exception("You didn't specify a valid endianness")
elif arch == "arm":
qemuDisk = "-drive if=none,file=image.raw,format=raw,id=rootfs -device virtio-blk-device,drive=rootfs"
qemuKernel = "./zImage"
qemu_rootfs = "/dev/vda1"
machine = "virt"
if endianness == "el":
qemu = "qemu-system-arm"
qemuEnvVars = "QEMU_AUDIO_DRV=none"
......
......@@ -13,4 +13,6 @@ KERNEL="${WORK_DIR}/zImage"
QEMU_AUDIO_DRV=none qemu-system-arm -m 256 -M virt -kernel ${KERNEL} -drive if=none,file=${IMAGE},format=raw,id=rootfs -device virtio-blk-device,drive=rootfs -append "firmadyne.syscall=1 root=/dev/vda1 console=ttyS0 nandsim.parts=64,64,64,64,64,64,64,64,64,64 rdinit=/firmadyne/preInit.sh rw debug ignore_loglevel print-fatal-signals=1 user_debug=31" -serial file:${WORK_DIR}/qemu.initial.serial.log -serial unix:/tmp/qemu.${IID}.S1,server,nowait -monitor unix:/tmp/qemu.${IID},server,nowait -display none -device virtio-net-device,netdev=net1 -netdev socket,listen=:2000,id=net1 -device virtio-net-device,netdev=net2 -netdev socket,listen=:2001,id=net2 -device virtio-net-device,netdev=net3 -netdev socket,listen=:2002,id=net3 -device virtio-net-device,netdev=net4 -netdev socket,listen=:2003,id=net4
QEMU_AUDIO_DRV=none ./qemu-system-arm -m 256 -M virt -kernel ${KERNEL} -drive if=none,file=${IMAGE},format=raw,id=rootfs -device virtio-blk-device,drive=rootfs -append "firmadyne.syscall=1 root=/dev/vda1 console=ttyS0 nandsim.parts=64,64,64,64,64,64,64,64,64,64 rdinit=/firmadyne/preInit.sh rw debug ignore_loglevel print-fatal-signals=1 user_debug=31" -serial file:${WORK_DIR}/qemu.initial.serial.log -serial unix:/tmp/qemu.${IID}.S1,server,nowait -monitor unix:/tmp/qemu.${IID},server,nowait -display none -device virtio-net-device,netdev=net1 -netdev socket,listen=:2000,id=net1 -device virtio-net-device,netdev=net2 -netdev socket,listen=:2001,id=net2 -device virtio-net-device,netdev=net3 -netdev socket,listen=:2002,id=net3 -device virtio-net-device,netdev=net4 -netdev socket,listen=:2003,id=net4
# QEMU_AUDIO_DRV=none qemu-system-arm -m 256 -M virt -kernel zImage -drive if=none,file="./image.raw",format=raw,id=rootfs -device virtio-blk-device,drive=rootfs -append "firmadyne.syscall=1 root=/dev/vda1 console=ttyS0 nandsim.parts=64,64,64,64,64,64,64,64,64,64 rdinit=/firmadyne/preInit.sh rw debug ignore_loglevel print-fatal-signals=1 user_debug=31" -serial file:"./qemu.initial.serial.log" -serial unix:/tmp/qemu.3.S1,server,nowait -monitor unix:/tmp/qemu.3,server,nowait -display none -device virtio-net-device,netdev=net1 -netdev socket,listen=:2000,id=net1 -device virtio-net-device,netdev=net2 -netdev socket,listen=:2001,id=net2 -device virtio-net-device,netdev=net3 -netdev socket,listen=:2002,id=net3 -device virtio-net-device,netdev=net4 -netdev socket,listen=:2003,id=net4
......@@ -20,7 +20,7 @@ chmod +x emu.py
chmod +x reset.py
#Set firmadyne_path in fat.config
sed -i "/firmadyne_path=/c\firmadyne_path=$firmadyne_dir" fat.config
sed -i "/firmadyne_path=/c\firmadyne_path=$firmadyne_dir" emu.config
# Comment out psql -d firmware ... in getArch.sh
sed -i 's/psql/#psql/' ./scripts/getArch.sh
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment