Closed AnyKeyShik closed 3 years ago
Is it my wrong or it is a PANDA bug?
Hi,
Apologies for the delay. It's been quite busy around here. Though I would say in regard to your second question that whether it is a PANDA bug or your bug you should still get a response (and ideally a more timely one).
I recreated your script and example program and have seen evidence that sys_pread64
is called on enter and return. I did the following:
C++ Example (copied and modified from here)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int fd = open("/root/example/test.txt", O_RDONLY);
if(fd < 0)
{
perror("open failed");
return 1;
}
char buf[1024] = {0};
int offset = 5;
ssize_t ret = 0;
int count = 10;
if((ret = pread(fd, buf, count, offset)) == -1)
{
perror("pread failed");
return 1;
}
std::cout << "read buf = " << buf << std::endl;
return 0;
}
Compile with c++ helloworld.cpp -o helloworld
And for my python script I used:
#!/usr/bin/env python3
from sys import argv
from pandare import Panda
panda = Panda(generic="x86_64")
@panda.queue_blocking
def run_cmd():
panda.revert_sync("root")
panda.copy_to_guest("example",timeout=1000)
print(panda.run_serial_cmd("/root/example/helloworld",timeout=60))
panda.end_analysis()
@panda.ppp("syscalls2", "on_sys_pread64_enter")
def pread_enter(cpu, *unused):
print(f"proc: {panda.get_process_name(cpu)} Pread64 enter")
@panda.ppp("syscalls2", "on_sys_pread64_return")
def pread_return(cpu, *unused):
print(f"proc: {panda.get_process_name(cpu)} Pread64 return")
panda.run()
Which prints out:
proc: helloworld Pread64 enter
proc: helloworld Pread64 return
read buf = fghijklmno
I would check a few things to start:
panda.run_serial_cmd("helloworld/hellworld")
command. I would note that it looks like "helloworld" is misspelled in the binary so that could be an issue.strace
to see if pread64 is called instead of some equivalent.If neither of these work you could provide the helloworld
source and I could look at it again from there.
Hi,
Apologies for the delay. It's been quite busy around here. Though I would say in regard to your second question that whether it is a PANDA bug or your bug you should still get a response (and ideally a more timely one).
I recreated your script and example program and have seen evidence that
sys_pread64
is called on enter and return. I did the following:C++ Example (copied and modified from here)
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <iostream> using namespace std; int main() { int fd = open("/root/example/test.txt", O_RDONLY); if(fd < 0) { perror("open failed"); return 1; } char buf[1024] = {0}; int offset = 5; ssize_t ret = 0; int count = 10; if((ret = pread(fd, buf, count, offset)) == -1) { perror("pread failed"); return 1; } std::cout << "read buf = " << buf << std::endl; return 0; }
Compile with
c++ helloworld.cpp -o helloworld
And for my python script I used:
#!/usr/bin/env python3 from sys import argv from pandare import Panda panda = Panda(generic="x86_64") @panda.queue_blocking def run_cmd(): panda.revert_sync("root") panda.copy_to_guest("example",timeout=1000) print(panda.run_serial_cmd("/root/example/helloworld",timeout=60)) panda.end_analysis() @panda.ppp("syscalls2", "on_sys_pread64_enter") def pread_enter(cpu, *unused): print(f"proc: {panda.get_process_name(cpu)} Pread64 enter") @panda.ppp("syscalls2", "on_sys_pread64_return") def pread_return(cpu, *unused): print(f"proc: {panda.get_process_name(cpu)} Pread64 return") panda.run()
Which prints out:
proc: helloworld Pread64 enter proc: helloworld Pread64 return read buf = fghijklmno
I would check a few things to start:
* The output of your `panda.run_serial_cmd("helloworld/hellworld")` command. I would note that it looks like "helloworld" is misspelled in the binary so that could be an issue. * The syscalls actually used by the program. Your program wasn't included so I couldn't check, but using `strace` to see if pread64 is called instead of some equivalent.
If neither of these work you could provide the
helloworld
source and I could look at it again from there.
Ty for your detailed answer. It really helped me, but I ran into another problem. How can I trace an x86 binary on an x86_64 system? When I try to run it PANDA just says me that file doesn't exist in system but I can grab info about it with ls, file and etc
My python script for tracing:
#! /usr/bin/env python3
from pandare import Panda
from cffi import FFI
from base64 import b64encode
import os
import json
ffi = FFI()
panda = Panda(generic="x86_64")
panda.require('osi')
panda.require('osi_linux')
# For files which opens by emulated program
opened_files = {}
# For store reads and writes
calls = {"read": [], "write": []}
# Binary file's name and its dir
filename = 'helloworld'
filepath = '/root/helloworld/helloworld'
dirname = 'helloworld'
@panda.queue_blocking
def drive_guest():
global dirname
global filepath
panda.revert_sync("root")
panda.copy_to_guest(dirname)
print( panda.run_serial_cmd('ls -las /root/helloworld') )
print( panda.run_serial_cmd('file /root/helloworld/helloworld') )
print( panda.run_serial_cmd('/root/helloworld/helloworld') )
panda.end_analysis()
@panda.ppp("syscalls2", "on_sys_openat_return")
def open(cpu, pc, flags, fname, *unused):
name = panda.get_process_name(cpu)
if name == filename:
filedesc = panda.plugins['syscalls2'].get_syscall_retval(cpu)
if filedesc < 0:
return
name = panda.read_str(cpu, fname)
opened_files[filedesc] = name
@panda.ppp("syscalls2", "on_sys_close_return")
def close(cpu, pc, fd):
name = panda.get_process_name(cpu)
if name == filename:
if fd in opened_files.keys():
opened_files.pop(fd)
@panda.ppp("syscalls2", "on_sys_read_return")
def read(cpu, pc, fd, buf, *unused):
name = panda.get_process_name(cpu)
if name == filename:
retval = panda.plugins['syscalls2'].get_syscall_retval(cpu)
if retval < 0:
print("FAIL READ :c")
return
data = b64encode(panda.virtual_memory_read(cpu, buf, retval)).decode('utf-8')
if fd in opened_files.keys():
fname = opened_files[fd]
else:
fname = "external file"
print(f"Read {data} from {fname}")
calls["read"].append({fname: data})
@panda.ppp("syscalls2", "on_sys_write_return")
def write(cpu, pc, fd, buf, *unused):
name = panda.get_process_name(cpu)
if name == filename:
retval = panda.plugins['syscalls2'].get_syscall_retval(cpu)
if retval < 0:
print("FAIL WRITE :c")
return
data = b64encode(panda.virtual_memory_read(cpu, buf, retval)).decode('utf-8')
if fd in opened_files.keys():
fname = opened_files[fd]
else:
fname = "external file"
print(f"Write {data} to {fname}")
calls["write"].append({fname: data})
panda.run()
And source of binary what I try to trace:
#include <stdio.h>
int
main(void)
{
FILE *out;
char *str;
out = fopen("./hello_out", "w");
str = "Hello world!\n";
if (!out) {
fprintf(stderr, "Error while opening out file!\n");
return -1;
}
fprintf(out, "%s", str);
printf("All files have been written!\n");
return 0;
}
How I can try to solve this problem?
UPD. Output of my script:
using generic x86_64
Loading libpanda from /usr/local/lib/python3.8/dist-packages/pandare/data
PANDA[core]:os_familyno=2 bits=64 os_details=ubuntu:4.15.0-72-generic-noaslr-nokaslr
[PYPANDA] Panda args: [/usr/local/lib/python3.8/dist-packages/pandare/data/x86_64-softmmu/libpanda-x86_64.so -L /usr/local/lib/python3.8/dist-packages/pandare/data/pc-bios /home/anykeyshik/.panda/bionic-server-cloudimg-amd64-noaslr-nokaslr.qcow2 -display none -m 1024 -serial unix:/tmp/pypanda_smxruf8t9,server,nowait -monitor unix:/tmp/pypanda_mmgcxrz7a,server,nowait]
PANDA[core]:loading required plugin osi
PANDA[core]:initializing osi
PANDA[core]:loading required plugin osi_linux
PANDA[core]:initializing osi_linux
PANDA[osi_linux]:W> kernelinfo bytes [20-23] not read
PANDA[core]:loading required plugin syscalls2
PANDA[core]:initializing syscalls2
PANDA[syscalls2]:using profile for linux x64 64-bit
PANDA[core]:loading required plugin hooks
PANDA[core]:initializing hooks
PANDA[core]:loading required plugin osi_linux
PANDA[core]:/usr/local/lib/python3.8/dist-packages/pandare/data//x86_64-softmmu/panda/plugins//panda_osi_linux.so already loaded
PPP automatically loaded plugin syscalls2
PANDA[core]:loading required plugin syscalls2
PANDA[core]:/usr/local/lib/python3.8/dist-packages/pandare/data//x86_64-softmmu/panda/plugins//panda_syscalls2.so already loaded
total 48
4 drwxrwxr-x 2 1000 1000 4096 Jul 27 2021 .
4 drwx------ 9 root root 4096 May 4 17:48 ..
20 -rwxr-xr-x 1 1000 1000 17488 Jul 27 2021 helloworld
20 -rwxr-xr-x 1 1000 1000 18608 Jul 27 2021 helloworld64
/root/helloworld/helloworld: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, BuildID[sha1]=fa1c062f8c124484d55af76e7c2e46c4fb64a24a, for GNU/Linux 4.4.0, with debug_info, not stripped
-bash: /root/helloworld/helloworld: No such file or directory
That's a general ubuntu multiarch problem. See: https://askubuntu.com/a/454452
Stale issue message
Seems like pread64 doesn't processed by syscalls2
Proof of concept: