Reverse-Engineering a Linux Process with strace

The pill you took is part of a trace program. It’s designed to disrupt your input/output carrier signals so we can pinpoint your location.

And just like that, we can trace signals as they bounce around the Matrix, whether it’s the Matrix that simulates Earth in 1999 or the Matrix that generates pretty pictures on the screen.

strace is a Linux program that functions much like a batch-mode debugger, tracing all library and system calls made by a process as it runs. It can be very useful for gaining insight into how a Linux program works under the hood, i.e. it’s a form of reverse engineering. I’ve been using it to examine the execution of some programs I have installed, just out of curiosity, and because seeing the proverbial Matrix code dumped to the computer screen gives me a raging mental boner.

To run strace, I’m using the options -r, -f, and -o. -r tells strace to print a relative timestamp for all library calls. This timestamp is relative to the last timestamp printed, not relative to the beginning of execution. -f tells strace to follow all forks and trace any child processes. -o specifies an output file for strace to write its output to. This option is important because if you try to use I/O redirection to send the output to a file, you’ll end up sending the output of the traced program, not of strace itself.

I wanted to see what I got when I traced NMap…


$ sudo strace -rfo strace-nmap.txt nmap workstation

Opening up the output file, we can see the inner workings of an NMap scan:


203287      0.000000 execve("/usr/bin/nmap"["nmap""workstation"]0x7ffffb2b0b58 /* 15 vars */) = 0
203287      0.000564 brk(NULL)          = 0x555afafe7000
203287      0.000227 arch_prctl(0x3001 /* ARCH_??? */0x7ffd662f7740) = -1 EINVAL (Invalid argument)
203287      0.000577 access("/etc/ld.so.preload"R_OK) = -1 ENOENT (No such file or directory)
203287      0.000393 openat(AT_FDCWD"/etc/ld.so.cache"O_RDONLY|O_CLOEXEC) = 3
203287      0.000214 newfstatat(3""{st_mode=S_IFREG|0644, st_size=56252, ...}AT_EMPTY_PATH) = 0
203287      0.000143 mmap(NULL56252PROT_READMAP_PRIVATE30) = 0x7fde37d7a000
203287      0.000082 close(3)           = 0
203287      0.000070 openat(AT_FDCWD"/usr/lib/libpcre.so.1"O_RDONLY|O_CLOEXEC) = 3
203287      0.000110 read(3"\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0  \0\0\0\0\0\0"..., 832) = 832
203287      0.000059 newfstatat(3""{st_mode=S_IFREG|0755, st_size=460544, ...}AT_EMPTY_PATH) = 0
203287      0.000055 mmap(NULL8192PROT_READ|PROT_WRITEMAP_PRIVATE|MAP_ANONYMOUS, -10) = 0x7fde37d78000
203287      0.000051 mmap(NULL463112PROT_READMAP_PRIVATE|MAP_DENYWRITE30) = 0x7fde37d06000
203287      0.000042 mmap(0x7fde37d08000327680PROT_READ|PROT_EXECMAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE30x2000) = 0x7fde37d08000
203287      0.000051 mmap(0x7fde37d58000122880PROT_READMAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE30x52000) = 0x7fde37d58000
203287      0.000048 mmap(0x7fde37d760008192PROT_READ|PROT_WRITEMAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE30x6f000) = 0x7fde37d76000
203287      0.000060 close(3)           = 0
203287      0.000042 openat(AT_FDCWD"/usr/lib/libpcap.so.1"O_RDONLY|O_CLOEXEC) = 3
203287      0.000065 read(3"\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@`\0\0\0\0\0\0"..., 832) = 832
203287      0.000052 newfstatat(3""{st_mode=S_IFREG|0755, st_size=317736, ...}AT_EMPTY_PATH) = 0
...
203287      0.000116 pselect6(6[5]NULLNULL{tv_sec=0, tv_nsec=2000000}NULL) = 0 (Timeout)
203287      0.002192 ioctl(3TIOCGPGRP0x7ffd662f63d4) = -1 ENOTTY (Inappropriate ioctl for device)
203287      0.000092 getpgrp()          = 203282
203287      0.000151 pselect6(6[5]NULLNULL{tv_sec=0, tv_nsec=2000000}NULL) = 0 (Timeout)
203287      0.002243 ioctl(3TIOCGPGRP0x7ffd662f63d4) = -1 ENOTTY (Inappropriate ioctl for device)
203287      0.000095 getpgrp()          = 203282
203287      0.000205 close(4)           = 0
203287      0.000105 setsockopt(5SOL_PACKETPACKET_RX_RING{tp_block_size=0, tp_block_nr=0, tp_frame_size=0, tp_frame_nr=0}16) = -1 EBUSY (Device or resource busy)
203287      0.000104 munmap(0x7fde36c770002129920) = 0
203287      0.000251 close(5)           = 0
203287      0.040563 write(1"Nmap scan report for workstation"..., 50) = 50
203287      0.000319 write(1"Host is up (0.00039s latency).\n"31) = 31
203287      0.000368 write(1"Not shown: 992 filtered ports\n"30) = 30
203287      0.000297 write(1"PORT      STATE SERVICE\n135/tcp "..., 216) = 216
203287      0.000125 write(1"MAC Address: 00:26:B9:B6:1E:7B ("..., 38) = 38
203287      0.000112 write(1"\n"1)  = 1
203287      0.000137 write(1"Nmap done: 1 IP address (1 host "..., 60) = 60
203287      0.000146 close(3)           = 0
203287      0.057997 exit_group(0)      = ?
203287      0.004111 +++ exited with 0 +++

Each line of this file has the following syntax:


PID	timestamp function( arguments ) = return_value

Remember that the PID and timestamp fields are only there because I used the -f and -r options respectively.

A few things I’ve noticed from examining the output file… First of all, arguments to a function are given as exact values, not symbols. If a read call is made, strace will show the literal string that was read from the file. Also, ASCII control codes inside strings are denoted by a backslash and then the ASCII code in octal format. Finally, strace is able to recognize certain numerical codes used in calls and substitute the appropriate macro names for those codes. This makes the trace output much easier to read.

There are a few insights about a program that can be gleaned from looking at this file. For one thing, adding up the timestamps in a program like awk can give you a precise measurement of the execution time, more precise than you would get from running the time command (only problem is there’s no division between user time and system time). The awk script I’ve written to do this is as follows (remember that this only works on files created using the -rf flags):


#!/usr/bin/awk -f
# Run on output of strace -rfo

BEGIN { FS = " "
        sum = 0 }
{ sum += $2 }
END { print( sum ) }

Another thing you can do is look at which libraries the program uses for its operation. This is shown by the sequences of openat/read/newfstatat/mmap/close calls towards the beginning of execution. For example:


203287      0.000042 openat(AT_FDCWD"/usr/lib/libpcap.so.1"O_RDONLY|O_CLOEXEC) = 3
203287      0.000065 read(3"\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@`\0\0\0\0\0\0"..., 832) = 832
203287      0.000052 newfstatat(3""{st_mode=S_IFREG|0755, st_size=317736, ...}AT_EMPTY_PATH) = 0
203287      0.000056 mmap(NULL320544PROT_READMAP_PRIVATE|MAP_DENYWRITE30) = 0x7fde37cb7000
203287      0.000043 mmap(0x7fde37cbd000172032PROT_READ|PROT_EXECMAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE30x6000) = 0x7fde37cbd000
203287      0.000048 mmap(0x7fde37ce7000114688PROT_READMAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE30x30000) = 0x7fde37ce7000
203287      0.000044 mmap(0x7fde37d0300012288PROT_READ|PROT_WRITEMAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE30x4b000) = 0x7fde37d03000
203287      0.000061 close(3)           = 0

Looking at all of these sequences, I determined that NMap makes use of the following libraries:

  • libc
  • libpcap
  • libm
  • libssh2
  • libssl
  • libcrypto
  • libgcrypt
  • libcre
  • liblua
  • libstdc++
  • libz
  • libzst
  • liblz4
  • liblzma
  • librt
  • libgpg
  • libpthread
  • libnl
  • libdl
  • libdbus
  • libsystemd

Since many of the library functions used by this program are not in my programming vocabulary, I’ve had to do a lot of research on the Arch Linux man pages. Most of the functions actually used in this particular program appear to be from libc, and the other libraries seem to be mostly used for specialized operations specified by different options. Since I used no options and just did a default scan, I don’t expect very many bells and whistles obviously.

One interesting thing that happens shortly after the shared libraries are mapped to memory is the following sequence:


203287      0.000070 openat(AT_FDCWD"/dev/urandom"O_RDONLY) = 3
203287      0.000115 read(3"\6\214\6!\20\333\245eA\325&\10\3728\200\1mh\246|\267\320\310\346z\312\21;\232\237\n\224"..., 236) = 236
203287      0.000078 close(3)           = 0

My educated guess is that /dev/urandom is used to generate an order for the port scan, since NMap randomizes the order in which ports are scanned by default. This is very similar to the truly random number generation algorithm I designed, which I talked about in this article. In that algorithm I used /dev/random instead of /dev/urandom.

The next highlight is the following code:


203287      0.000038 stat("/root/.nmap/nmap-services"0x7ffd662f5800) = -1 ENOENT (No such file or directory)
203287      0.000048 getuid()           = 0
203287      0.000032 geteuid()          = 0
203287      0.000032 readlink("/proc/self/exe""/usr/bin/nmap"1024) = 13
203287      0.000088 stat("/usr/bin/nmap-services"0x7ffd662f5800) = -1 ENOENT (No such file or directory)
203287      0.000049 stat("/usr/bin/../share/nmap/nmap-services"{st_mode=S_IFREG|0644, st_size=1001818, ...}) = 0
203287      0.000057 access("/usr/bin/../share/nmap/nmap-services"R_OK) = 0
203287      0.000046 stat("./nmap-services"0x7ffd662f5800) = -1 ENOENT (No such file or directory)
203287      0.000047 openat(AT_FDCWD"/usr/bin/../share/nmap/nmap-services"O_RDONLY) = 3
203287      0.000053 newfstatat(3""{st_mode=S_IFREG|0644, st_size=1001818, ...}AT_EMPTY_PATH) = 0
203287      0.000047 read(3"# THIS FILE IS GENERATED AUTOMAT"..., 1024) = 1024
203287      0.000043 read(3"Fields in this file are: Service"..., 1024) = 1024
203287      0.000101 read(3"he Day\nqotd\t17/udp\t0.009209\t# Qu"..., 1024) = 1024
203287      0.000077 read(3"\t0.001285\t# Simple Mail Transfer"..., 1024) = 1024
203287      0.000079 read(3"t Name Server\nwhois\t43/tcp\t0.000"..., 1024) = 1024
203287      0.000076 read(3"/udp\t0.213496\t# Domain Name Serv"..., 1024) = 1024
203287      0.000067 read(3"\t# TACACS-Database Service\ntacac"..., 1024) = 1024
203287      0.000065 read(3"t service\npriv-dial\t75/udp\t0.000"..., 1024) = 1024
203287      0.000068 read(3".000824\t# Micro Focus Cobol\npriv"..., 1024) = 1024
203287      0.000065 read(3"rotocol\nswift-rvf\t97/udp\t0.00036"..., 1024) = 1024
203287      0.000062 read(3"ora compatible PW changer | 3COM"..., 1024) = 1024
203287      0.000064 read(3"p\t0.000025\t# Simple File Transfe"..., 1024) = 1024
203287      0.000074 read(3" | Unisys Unitary Login | NXEdit"..., 1024) = 1024
203287      0.000071 read(3"025\t# PROFILE Naming System\nprof"..., 1024) = 1024
203287      0.000071 read(3"UAAC Protocol\niso-tp0\t146/tcp\t0."..., 1024) = 1024
203287      0.000081 read(3"-routing\t159/udp\t0.000329\nsgmp-t"..., 1024) = 1024
203287      0.000077 read(3"3/tcp\t0.000013\t# Xyplex\nxyplex-m"..., 1024) = 1024
203287      0.000079 read(3"ol\naci\t187/tcp\t0.000000\t# Applic"..., 1024) = 1024
203287      0.000074 read(3".000025\t# DNSIX Session Mgt Modu"..., 1024) = 1024
203287      0.000072 read(3"ion\nat-zis\t206/udp\t0.000956\t# Ap"..., 1024) = 1024
203287      0.000072 read(3"nology License Server\ndbase\t217/"..., 1024) = 1024
203287      0.000077 read(3"35/tcp\t0.000025\nunknown\t236/tcp\t"..., 1024) = 1024
203287      0.000082 read(3"ion (set) port | Secure Electron"..., 1024) = 1024
203287      0.000072 read(3"td-service\t267/udp\t0.000000\t# To"..., 1024) = 1024
203287      0.000079 read(3"K-BLOCK\nunknown\t288/tcp\t0.000013"..., 1024) = 1024
203287      0.000086 read(3"0.000346\npkix-timestamp\t318/tcp\t"..., 1024) = 1024
203287      0.000082 read(3"pawserv\t345/udp\t0.000428\t# Perf "..., 1024) = 1024
203287      0.000079 read(3"p\t358/udp\t0.000445\ntenebris_nts\t"..., 1024) = 1024
203287      0.000078 read(3"v | ListProcessor\nulistserv\t372/"..., 1024) = 1024
203287      0.000072 read(3"llector\t381/udp\t0.000577\t# hp pe"..., 1024) = 1024
203287      0.000072 read(3"p\t0.000478\nsynotics-relay\t391/tc"..., 1024) = 1024
203287      0.000069 read(3"99/udp\t0.000395\t# ISO-TSAP Class"..., 1024) = 1024
203287      0.000073 read(3"ol\nrmt\t411/tcp\t0.000088\t# Remote"..., 1024) = 1024
203287      0.000064 brk(0x555afb04d000) = 0x555afb04d000
203287      0.000057 read(3"\t424/udp\t0.000610\t# IBM Operatio"..., 1024) = 1024
203287      0.000090 read(3"1/udp\t0.000395\ncvc_hostd\t442/tcp"..., 1024) = 1024
203287      0.000077 read(3".000013\t# Cray SFS config server"..., 1024) = 1024
...

The file the program is reading is basically a version of /etc/services. It tells NMap which services are running on which ports.

Shortly after this, we can see several calls to the socket() function in the Sockets API. Most of the sockets opened are either datagram sockets or Unix domain sockets, though there are a handful of raw sockets as well. It’s difficult to tell what all of them are for. I’m guessing the bulk of the port scans are done using datagram sockets. Here is a sample of the socket code:


203287      0.000116 socket(AF_NETLINKSOCK_RAWNETLINK_ROUTE) = 3
203287      0.000086 bind(3{sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}12) = 0
203287      0.000088 sendmsg(3{msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base={{nlmsg_len=36, nlmsg_type=RTM_GETROUTE, nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}{rtm_family=AF_INET, rtm_dst_len=32, rtm_src_len=0, rtm_tos=0, rtm_table=RT_TABLE_UNSPEC, rtm_protocol=RTPROT_UNSPEC, rtm_scope=RT_SCOPE_UNIVERSE, rtm_type=RTN_UNSPEC, rtm_flags=0}{{nla_len=8, nla_type=RTA_DST}, inet_addr("192.168.10.102")}}, iov_len=36}], msg_iovlen=1, msg_controllen=0, msg_flags=0}0) = 36
203287      0.000414 recvmsg(3{msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base={{nlmsg_len=104, nlmsg_type=RTM_NEWROUTE, nlmsg_flags=0, nlmsg_seq=0, nlmsg_pid=203287}{rtm_family=AF_INET, rtm_dst_len=32, rtm_src_len=0, rtm_tos=0, rtm_table=RT_TABLE_MAIN, rtm_protocol=RTPROT_UNSPEC, rtm_scope=RT_SCOPE_UNIVERSE, rtm_type=RTN_UNICAST, rtm_flags=RTM_F_CLONED}[{{nla_len=8, nla_type=RTA_TABLE}RT_TABLE_MAIN}{{nla_len=8, nla_type=RTA_DST}, inet_addr("192.168.10.102")}{{nla_len=8, nla_type=RTA_OIF}, if_nametoindex("enp0s25")}{{nla_len=8, nla_type=RTA_PREFSRC}, inet_addr("192.168.10.117")}{{nla_len=8, nla_type=RTA_UID}0}{{nla_len=36, nla_type=RTA_CACHEINFO}{rta_clntref=4, rta_lastuse=150028827, rta_expires=0, rta_error=0, rta_used=0, rta_id=0, rta_ts=0, rta_tsage=0}}]}, iov_len=512}], msg_iovlen=1, msg_controllen=0, msg_flags=0}0) = 104
203287      0.000218 close(3)           = 0
203287      0.000080 access("/proc/net"R_OK) = 0
203287      0.000102 access("/proc/net/unix"R_OK) = 0
203287      0.000102 socket(AF_UNIXSOCK_DGRAM|SOCK_CLOEXEC0) = 3
203287      0.000082 ioctl(3SIOCGIFNAME{ifr_ifindex=2, ifr_name="enp0s25"}) = 0
203287      0.000092 close(3)           = 0
203287      0.000099 socket(AF_INETSOCK_DGRAMIPPROTO_IP) = 3
203287      0.000083 setsockopt(3SOL_SOCKETSO_BROADCAST[1]4) = 0
203287      0.000092 openat(AT_FDCWD"/proc/net/dev"O_RDONLY) = 4
203287      0.000109 ioctl(3SIOCGIFCONF{ifc_len=4192 => 3 * sizeof(struct ifreq), ifc_buf=[{ifr_name="lo", ifr_addr={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}}{ifr_name="enp0s25", ifr_addr={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("192.168.10.117")}}{ifr_name="enp0s25", ifr_addr={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("192.168.10.118")}}]}) = 0
203287      0.000113 newfstatat(4""{st_mode=S_IFREG|0444, st_size=0, ...}AT_EMPTY_PATH) = 0
203287      0.000095 read(4"Inter-|   Receive               "..., 1024) = 572
203287      0.000157 socket(AF_UNIXSOCK_DGRAM|SOCK_CLOEXEC0) = 5
203287      0.000085 ioctl(5SIOCGIFINDEX{ifr_name="lo", ifr_ifindex=1}) = 0
203287      0.000102 close(5)           = 0
203287      0.000080 ioctl(3SIOCGIFFLAGS{ifr_name="lo", ifr_flags=IFF_UP|IFF_LOOPBACK|IFF_RUNNING}) = 0
203287      0.000090 ioctl(3SIOCGIFMTU{ifr_name="lo", ifr_mtu=65536}) = 0
203287      0.000086 ioctl(3SIOCGIFADDR{ifr_name="lo", ifr_addr={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}}) = 0
203287      0.000091 ioctl(3SIOCGIFNETMASK{ifr_name="lo", ifr_netmask={sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("255.0.0.0")}}) = 0
203287      0.000112 openat(AT_FDCWD"/proc/net/if_inet6"O_RDONLY) = 5
203287      0.000119 newfstatat(5""{st_mode=S_IFREG|0444, st_size=0, ...}AT_EMPTY_PATH) = 0
203287      0.000098 read(5"fe80000000000000021f16fffe3821a4"..., 1024) = 108
203287      0.000115 read(5""1024)  = 0
203287      0.000073 close(5)           = 0

Shortly after this we can see the actual scans taking place, where ports are scanned in an arbitrary order:


203287      0.000282 sendto(4"E\0\0,5\335\0\0/\6\277\303\300\250\nu\300\250\nf\357\30\0Px\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("192.168.10.102")}16) = 44
203287      0.000235 sendto(4"E\0\0,\32\213\0\0:\6\320\25\300\250\nu\300\250\nf\357\30\4\1x\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(1025), sin_addr=inet_addr("192.168.10.102")}16) = 44
203287      0.000174 sendto(4"E\0\0,GK\0\0002\6\253U\300\250\nu\300\250\nf\357\30\0qx\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(113), sin_addr=inet_addr("192.168.10.102")}16) = 44
203287      0.000220 sendto(4"E\0\0,b[\0\0)\6\231E\300\250\nu\300\250\nf\357\30\37\220x\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.168.10.102")}16) = 44
203287      0.000208 sendto(4"E\0\0,6\2\0\0,\6\302\236\300\250\nu\300\250\nf\357\30\1\0x\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(256), sin_addr=inet_addr("192.168.10.102")}16) = 44
203287      0.000205 sendto(4"E\0\0,\323\364\0\0,\6$\254\300\250\nu\300\250\nf\357\30\0\207x\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(135), sin_addr=inet_addr("192.168.10.102")}16) = 44
203287      0.000204 sendto(4"E\0\0,1\323\0\0006\6\274\315\300\250\nu\300\250\nf\357\30\0\26x\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("192.168.10.102")}16) = 44
203287      0.000223 sendto(4"E\0\0,\325\346\0\0.\6 \272\300\250\nu\300\250\nf\357\30\1\275x\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(445), sin_addr=inet_addr("192.168.10.102")}16) = 44
203287      0.000330 sendto(4"E\0\0,\257\215\0\09\6<\23\300\250\nu\300\250\nf\357\30\r=x\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(3389), sin_addr=inet_addr("192.168.10.102")}16) = 44
203287      0.000326 sendto(4"E\0\0,i\345\0\0002\6\210\273\300\250\nu\300\250\nf\357\30\0\307x\217+\217\0\0\0\0"..., 440{sa_family=AF_INET, sin_port=htons(199), sin_addr=inet_addr("192.168.10.102")}16) = 44

The program continues like this for most of the rest of its execution, with some recvfrom() and pselect6() functions used as well. According to the man page, pselect6 is a variation of select, which is used by a program to monitor multiple file descriptors at once. Here the multiple file descriptors would be the different sockets it’s using to communicate with the target, where it’s waiting for a response on each of those sockets.

After all the scan signals have been sent out and messages received on any open ports, the program will receive a series of timeouts from ports that do not have services running on them (which will be the vast majority of them):


203287      0.000103 pselect6(6[5]NULLNULL{tv_sec=0, tv_nsec=2000000}NULL) = 0 (Timeout)
203287      0.002192 ioctl(3TIOCGPGRP0x7ffd662f63d4) = -1 ENOTTY (Inappropriate ioctl for device)
203287      0.000091 getpgrp()          = 203282
203287      0.000103 pselect6(6[5]NULLNULL{tv_sec=0, tv_nsec=2000000}NULL) = 0 (Timeout)
203287      0.002192 ioctl(3TIOCGPGRP0x7ffd662f63d4) = -1 ENOTTY (Inappropriate ioctl for device)
203287      0.000092 getpgrp()          = 203282
203287      0.000104 pselect6(6[5]NULLNULL{tv_sec=0, tv_nsec=2000000}NULL) = 0 (Timeout)
203287      0.002189 ioctl(3TIOCGPGRP0x7ffd662f63d4) = -1 ENOTTY (Inappropriate ioctl for device)
203287      0.000093 getpgrp()          = 203282
203287      0.000102 pselect6(6[5]NULLNULL{tv_sec=0, tv_nsec=2000000}NULL) = 0 (Timeout)
203287      0.002192 ioctl(3TIOCGPGRP0x7ffd662f63d4) = -1 ENOTTY (Inappropriate ioctl for device)
203287      0.000092 getpgrp()          = 203282
203287      0.000116 pselect6(6[5]NULLNULL{tv_sec=0, tv_nsec=2000000}NULL) = 0 (Timeout)
203287      0.002192 ioctl(3TIOCGPGRP0x7ffd662f63d4) = -1 ENOTTY (Inappropriate ioctl for device)
203287      0.000092 getpgrp()          = 203282
203287      0.000151 pselect6(6[5]NULLNULL{tv_sec=0, tv_nsec=2000000}NULL) = 0 (Timeout)
203287      0.002243 ioctl(3TIOCGPGRP0x7ffd662f63d4) = -1 ENOTTY (Inappropriate ioctl for device)
203287      0.000095 getpgrp()          = 203282

The final part of the program is when it prints the scan report and then exits with a status of 0:


203287      0.040563 write(1"Nmap scan report for workstation"..., 50) = 50
203287      0.000319 write(1"Host is up (0.00039s latency).\n"31) = 31
203287      0.000368 write(1"Not shown: 992 filtered ports\n"30) = 30
203287      0.000297 write(1"PORT      STATE SERVICE\n135/tcp "..., 216) = 216
203287      0.000125 write(1"MAC Address: 00:26:B9:B6:1E:7B ("..., 38) = 38
203287      0.000112 write(1"\n"1)  = 1
203287      0.000137 write(1"Nmap done: 1 IP address (1 host "..., 60) = 60
203287      0.000146 close(3)           = 0
203287      0.057997 exit_group(0)      = ?
203287      0.004111 +++ exited with 0 +++

And that, in essence, is the execution of a basic port scan, traced from start to finish. I think I like strace. 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s