tcpsnitch
เป็นเครื่องมือติดตามที่ออกแบบมาเพื่อตรวจสอบการโต้ตอบระหว่างแอปพลิเคชันและสแต็ก TCP/IP tcpsnitch
รันคำสั่งที่ระบุจนกว่าจะออกและขัดขวางการเรียกฟังก์ชัน libc ทั้งหมดบนซ็อกเก็ตอินเทอร์เน็ต
ในการเริ่มต้นอย่างนุ่มนวล อาจเรียกใช้คำสั่งต่อไปนี้เพื่อติดตามโปรแกรม curl
:
$ tcpsnitch curl google.com
สำหรับซ็อกเก็ตอินเทอร์เน็ตที่เปิดอยู่แต่ละซ็อกเก็ต tcpsnitch
จะสร้างรายการการเรียกใช้ฟังก์ชันตามลำดับ (การเรียกใช้ฟังก์ชันเรียกว่า เหตุการณ์ ในส่วนที่เหลือของเอกสารนี้) สำหรับแต่ละเหตุการณ์ tcpsnitch
จะบันทึกอาร์กิวเมนต์ ค่าที่ส่งคืน และข้อมูลต่างๆ เช่น การประทับเวลาปัจจุบันหรือรหัสเธรด โดยเฉพาะอย่างยิ่ง เหตุการณ์ connect()
อาจมีลักษณะเช่นนี้ในการติดตามซ็อกเก็ต:
{
"type" : " connect " ,
"timestamp_usec" : 1491043720731853 ,
"return_value" : 0 ,
"success" : true ,
"thread_id" : 17313 ,
"details" : {
"addr" : {
"sa_family" : " AF_INET " ,
"ip" : " 127.0.1.1 " ,
"port" : " 53 "
}
}
}
การติดตามซ็อกเก็ตจะถูกเขียนลงในไฟล์ข้อความโดยที่แต่ละบรรทัดเป็นออบเจ็กต์ JSON ที่แสดงถึงเหตุการณ์เดียว หัวหน้าของร่องรอยอาจเป็นดังนี้:
{ "type" : " socket " , "timestamp_usec" : 1491043720731840 , "return_value" : 6 , "success" : true , "thread_id" : 17313 , "details" : { "sock_info" : { "domain" : " AF_INET " , "type" : " SOCK_DGRAM " , "protocol" : 0 , "SOCK_CLOEXEC" : false , "SOCK_NONBLOCK" : true }}}
{ "type" : " ioctl " , "timestamp_usec" : 1491043720765019 , "return_value" : 0 , "success" : true , "thread_id" : 17313 , "details" : { "request" : " FIONREAD " }}
{ "type" : " recvfrom " , "timestamp_usec" : 1491043720765027 , "return_value" : 44 , "success" : true , "thread_id" : 17313 , "details" : { "bytes" : 2048 , "flags" : { "MSG_CMSG_CLOEXEC" : false , "MSG_DONTWAIT" : false , "MSG_ERRQUEUE" : false , "MSG_OOB" : false , "MSG_PEEK" : false , "MSG_TRUNC" : false , "MSG_WAITALL" : false }, "addr" : { "sa_family" : " AF_INET " , "ip" : " 127.0.1.1 " , "port" : " 53 " }}}
{ "type" : " ioctl " , "timestamp_usec" : 1491043720770075 , "return_value" : 0 , "success" : true , "thread_id" : 17313 , "details" : { "request" : " FIONREAD " }}
{ "type" : " recvfrom " , "timestamp_usec" : 1491043720770094 , "return_value" : 56 , "success" : true , "thread_id" : 17313 , "details" : { "bytes" : 65536 , "flags" : { "MSG_CMSG_CLOEXEC" : false , "MSG_DONTWAIT" : false , "MSG_ERRQUEUE" : false , "MSG_OOB" : false , "MSG_PEEK" : false , "MSG_TRUNC" : false , "MSG_WAITALL" : false }, "addr" : { "sa_family" : " AF_INET " , "ip" : " 127.0.1.1 " , "port" : " 53 " }}}
เนื่องจากคำสั่งเดียวอาจแยกหลายกระบวนการ (และ tcpsnitch
ตามหลังส้อม) การติดตามซ็อกเก็ตทั้งหมดที่เป็นของกระบวนการที่กำหนดจะถูกรวมเข้าด้วยกันในไดเร็กทอรีซึ่งตั้งชื่อตามกระบวนการที่ติดตาม ภายในไดเร็กทอรีดังกล่าว การติดตามซ็อกเก็ตจะถูกตั้งชื่อตามลำดับที่เปิดโดยกระบวนการ
ตามค่าเริ่มต้น การติดตามจะถูกบันทึกในไดเรกทอรีสุ่มภายใต้ /tmp
และอัปโหลดไปยัง www.tcpsnitch.org โดยอัตโนมัติ ซึ่งเป็นแพลตฟอร์มที่ออกแบบมาเพื่อรวมศูนย์ แสดงภาพ และวิเคราะห์การติดตาม โปรดทราบว่าการติดตามที่อัปโหลดทั้งหมดเป็นแบบสาธารณะและพร้อมให้ทุกคนปรึกษาและดาวน์โหลดได้
ตามที่ปรากฏในข้อมูลโค้ดถัดไป tcpsnitch
จะให้ URL ที่การติดตามของคุณพร้อมใช้งาน
$ tcpsnitch curl google.com
Trace saved in /tmp/tmp.4ERKizKyU3.
Uploading trace....
Trace successfully uploaded at https://tcpsnitch.org/app_traces/20.
Trace archive will be imported shortly. Refresh this page in a few minutes...
โปรดทราบว่าต้องใช้เวลาหลายนาทีในการนำเข้าการติดตาม (เช่น แยกไฟล์เก็บถาวรการติดตามและแทรกเหตุการณ์ทั้งหมดในฐานข้อมูล) เมื่อนำเข้าแล้ว อาจต้องใช้เวลาอีกหลายนาทีในการคำนวณการวิเคราะห์เชิงปริมาณของร่องรอย
สุดท้ายนี้ tcpsnitch
ยังอนุญาตให้แยกตัวเลือกซ็อกเก็ต TCP_INFO
ตามช่วงเวลาที่ผู้ใช้กำหนด และบันทึกการติดตาม .pcap
สำหรับแต่ละซ็อกเก็ตแต่ละซ็อกเก็ต ดูส่วนการใช้งานสำหรับข้อมูลเพิ่มเติม
tcpsnitch
อนุญาตให้ติดตามแอปพลิเคชันบน:
เนื่องจาก tcpsnitch
ทำงานโดยการสกัดกั้นการเรียกฟังก์ชัน libc โดยใช้ตัวแปรสภาพแวดล้อม LD_PRELOAD
การติดตามจึงไม่สามารถทำได้สำหรับแอปพลิเคชันที่เชื่อมโยงแบบคงที่กับ libc
หมายเหตุ: บน Linux Chrome (และแอปที่ใช้ Chromium เช่น Electron, Opera ฯลฯ...) เป็นที่ทราบกันว่าเข้ากันไม่ได้
สำหรับผู้ใช้ที่ต้องการติดตามแอปพลิเคชัน Android ให้เลื่อนลงไปที่ส่วน "การคอมไพล์สำหรับ Android"
ทดสอบบน Ubuntu 16 และ 14, Debian 8, Elementary 0.4, Mint 18
sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt-get install make gcc gcc-multilib libc6-dev libc6-dev:i386 libjansson-dev libjansson-dev:i386 libpcap0.8 libpcap0.8:i386 libpcap0.8-dev
ทดสอบบน Fedora 25 และ CentOS 7
sudo yum install make gcc glibc-devel glibc-devel.i686 libgcc libgcc.i686 libpcap-devel.x86_64 libpcap-devel.i686 jansson jansson.i686 && curl -O http://www.digip.org/jansson/releases/jansson-2.10.tar.bz2 && bunzip2 -c jansson-2.10.tar.bz2 | tar xf - && rm -f jansson-2.10.tar.bz2 && cd jansson-2.10 && ./configure && make && sudo make install && cd .. && rm -rf jansson-2.10
สร้างและติดตั้ง:
./configure
make
sudo make install
การใช้งาน: tcpsnitch [<options>] <cmd> [<cmd_args>]
โดยที่:
<options>
คือตัวเลือก tcpsnitch
<cmd>
เป็นคำสั่งในการติดตาม (จำเป็น)<cmd_args>
เป็นอาร์กิวเมนต์ของ <cmd>
นี่คือตัวอย่างง่ายๆ ที่มี curl
และตัวเลือกเริ่มต้นทั้งหมด:
tcpsnitch curl google.com
อาจออก tcpsnitch -h
เพื่อรับข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกที่รองรับ สิ่งที่สำคัญที่สุดมีดังต่อไปนี้:
-b
และ -u
ใช้สำหรับแยก TCP_INFO
ตามช่วงเวลาที่ผู้ใช้กำหนด ดูส่วน "การแยก TCP_INFO
" สำหรับข้อมูลเพิ่มเติม-c
ใช้สำหรับจับร่องรอย pcap
ของซ็อกเก็ต ดูส่วน "การจับแพ็คเก็ต" สำหรับข้อมูลเพิ่มเติม-a
และ -k
ใช้สำหรับติดตามแอปพลิเคชัน Android ดูส่วน "การใช้งาน Android" สำหรับข้อมูลเพิ่มเติม-n
ปิดใช้งานการอัปโหลดการติดตามอัตโนมัติ-d
ตั้งค่าไดเร็กทอรีที่จะเขียนการติดตาม (แทนที่จะเป็นไดเร็กทอรีสุ่มใน /tmp
)-f
ตั้งค่าระดับรายละเอียดของบันทึกที่บันทึกไว้ในไฟล์ ตามค่าเริ่มต้น เฉพาะข้อความเตือนและข้อผิดพลาดเท่านั้นที่จะถูกเขียนลงในบันทึก สิ่งนี้มีประโยชน์สำหรับการรายงานจุดบกพร่องและการดีบักเป็นหลัก-l
คล้ายกับ -f
แต่ตั้งค่าความละเอียดของบันทึกใน STDOUT ซึ่งตามค่าเริ่มต้นจะแสดงเฉพาะข้อความ ERROR สิ่งนี้ใช้เพื่อวัตถุประสงค์ในการแก้ไขจุดบกพร่อง-t
ควบคุมความถี่ที่เหตุการณ์ถูกดัมพ์ไปยังไฟล์ ตามค่าเริ่มต้น เหตุการณ์จะถูกเขียนลงในไฟล์ทุกๆ 1,000 มิลลิวินาที-v
ค่อนข้างไร้ประโยชน์ในขณะนี้ แต่ควรจะใส่ tcpsnitch
ในโหมด verbose ในรูปแบบของ strace
ยังคงต้องดำเนินการ (ขณะนี้แสดงเฉพาะชื่อเหตุการณ์เท่านั้น)TCP_INFO
-b <bytes>
และ -u <usec>
อนุญาตให้แยกค่าของตัวเลือกซ็อกเก็ต TCP_INFO
สำหรับแต่ละซ็อกเก็ตตามช่วงเวลาที่ผู้ใช้กำหนด โปรดทราบว่าค่า TCP_INFO
จะปรากฏเป็นเหตุการณ์อื่นๆ ในการติดตาม JSON ของ socekt
-b <bytes>
, TCP_INFO
จะถูกบันทึกทุกๆ <bytes>
ที่ส่ง+รับบนซ็อกเก็ต-u <usec>
TCP_INFO
จะถูกบันทึกทุกๆ <usec>
ไมโครวินาทีTCP_INFO
จะถูกบันทึกเมื่อเงื่อนไขข้อใดข้อหนึ่งตรงกัน ตามค่าเริ่มต้น ตัวเลือกนี้จะปิดอยู่ โปรดทราบว่า tcpsnitch
จะตรวจสอบเงื่อนไขเหล่านี้เมื่อมีการเรียกใช้ฟังก์ชันที่ถูกแทนที่เท่านั้น
ตัวเลือก -c
เปิดใช้งานการจับการติดตาม .pcap
สำหรับแต่ละซ็อกเก็ต โปรดทราบว่าคุณต้องมีสิทธิ์ที่เหมาะสมเพื่อให้สามารถบันทึกการรับส่งข้อมูลบนอินเทอร์เฟซได้ (ดูข้อมูลเพิ่มเติมเกี่ยวกับการอนุญาตดัง man pcap
)
คุณลักษณะนี้ยังไม่พร้อมใช้งานสำหรับ Android ในขณะนี้
การใช้งานบน Android เป็นกระบวนการสองขั้นตอน คล้ายกับการใช้งานบน Linux มาก ขั้นแรก ให้ตั้งค่า tcpsnitch
และเปิดแอปพลิเคชันเพื่อติดตามด้วยตัวเลือกที่เหมาะสม จากนั้นติดตามจะถูกดึงออกจากอุปกรณ์และคัดลอกไปยังเครื่องโฮสต์
ตัวเลือกทั้งหมดได้รับการสนับสนุนบน Android ยกเว้นตัวเลือก -c
สำหรับการติดตามการติดตาม .pcap
ต้องทำขั้นตอนการตั้งค่าเบื้องต้นบางอย่างบนอุปกรณ์เพียงครั้งเดียว:
adb devices
และตรวจสอบให้แน่ใจว่าโทรศัพท์ของคุณมองเห็นได้ (คุณควรเห็น device
ในคอลัมน์ที่สอง) เมื่อเข้าถึงอุปกรณ์ผ่าน adb
การใช้งานจะเกือบจะเหมือนกับบน Linux:
tcpsnitch
ปกติด้วยตัวเลือก -a
เพื่อระบุว่าคุณต้องการติดตามแอปพลิเคชันบนอุปกรณ์ Android ที่เชื่อมต่อ โปรดทราบว่าอาร์กิวเมนต์ <cmd>
ต้องตรงกับชื่อของแพ็คเกจที่ติดตั้งบนอุปกรณ์ผ่าน grep
แบบธรรมดา ตัวอย่างเช่น หากต้องการติดตามแอปพลิเคชัน Firefox ที่มีชื่อแพ็คเกจเป็น org.firefox.com
เราอาจออก tcpsnitch -a firefox
tcpsnitch
จะแจ้งให้คุณทราบถึงแพ็คเกจที่ตรงกันที่พบและเริ่มแอปพลิเคชันทันทีtcpsnitch -k <package>
เพื่อหยุดการทำงานของแอปพลิเคชันและยุติกระบวนการติดตาม การติดตามจะถูกดึงออกจากอุปกรณ์และบันทึกไว้บนดิสก์ของคุณใน /tmp
ก่อนที่จะอัปโหลดไปยัง www.tcpsnitch.org สำคัญ: คุณต้องรีสตาร์ทอุปกรณ์ Android ของคุณเพื่อปิดใช้งานการติดตามโดยสมบูรณ์ เนื่องจาก tcpsnitch
ใช้คุณสมบัติของ Android ในการตั้งค่าไลบรารี LD_PRELOAD
และคุณสมบัติเหล่านี้ไม่สามารถยกเลิกการตั้งค่าได้ จึงต้องทำการรีบูตอุปกรณ์เพื่อลบคุณสมบัติ (อาจมีบางคนรู้วิธีแก้ปัญหาที่ดีกว่านี้)
นี่คือตัวอย่างแบบเต็มสำหรับการติดตาม Firefox:
$ tcpsnitch -a firefox
Found Android package: ' org.mozilla.firefox ' .
Uploading tcpsnitch library to /data/libtcpsnitch.so.0.1-arm.
Start package ' org.mozilla.firefox ' .
Execute ' ./tcpsnitch -k firefox ' to terminate the capture.
# INTERACTING WITH APPLICATION
$ tcpsnitch -k firefox
Found Android package: ' org.mozilla.firefox ' .
Pulling trace from Android device....
Trace saved in /tmp/tmp.MidCH9rm3x.
Uploading trace....
Trace successfully uploaded at https://tcpsnitch.org/app_traces/21.
Trace archive will be imported shortly. Refresh this page in a few minutes...
โปรดทราบว่าในกรณีที่มีการจับคู่หลายรายการสำหรับแพ็คเกจหนึ่งๆ ระบบจะใช้แพ็คเกจที่ตรงกันรายการแรก คุณอาจต้องเจาะจงมากขึ้นเพื่อหลีกเลี่ยงความขัดแย้ง คุณสามารถรัน adb shell pm list packages
เพื่อรับชื่อของแพ็คเกจทั้งหมดที่ติดตั้งบนอุปกรณ์ของคุณ
โปรดทราบว่า adb
ต้องมองเห็นอุปกรณ์เครื่องเดียว
ในการติดตามแอปพลิเคชัน Android นั้น tcpsnitch
จะต้องคอมไพล์ด้วย Android Native Development Kit (NDK) การคอมไพล์มีส่วนร่วมมากกว่าและการตั้งค่าต้องใช้อุปกรณ์ Android ที่รูท
โดยพื้นฐานแล้วจะเกี่ยวข้องกับขั้นตอนต่อไปนี้:
libjansson
และ libpcap
ด้วย NDK และทำให้ไลบรารีที่คอมไพล์แล้วและไฟล์ส่วนหัวพร้อมใช้งานสำหรับ toolchain แบบสแตนด์อโลนtcpsnitch
ด้วย toolchain แบบสแตนด์อโลนและเตรียมอุปกรณ์ Androidส่วนต่อไปนี้จะแสดงตัวอย่างที่ซับซ้อนซึ่งจะอธิบายคุณตลอดทุกขั้นตอน
สมมติฐานบางประการ:
<NDK_PATH>
<TCPSNITCH_PATH>
ขั้นแรก เรามากำหนดตัวแปรสองสามตัวกัน:
export TCPSNITCH=<TCPSNITCH_PATH>
export NDK=<NDK_PATH>
# Where the standalone toolchain WILL be created
export TOOLCHAIN=<TOOLCHAIN_PATH>
ตอนนี้ เรามาเริ่มต้นด้วยการสร้าง toolchain แบบสแตนด์อโลนสำหรับอุปกรณ์ ARM ที่ใช้ Android API 23 (เวอร์ชัน 6.0, Marshmallow) การแมประหว่างเวอร์ชัน Android และระดับ API ในหน้าต่อไปนี้
$NDK/build/tools/make_standalone_toolchain.py --arch arm --api 23 --install-dir $TOOLCHAIN
ตอนนี้เราต้องรวบรวมทั้ง libjansson
และ libpcap
ด้วย NDK เมื่อเสร็จแล้ว เราต้องติดตั้งไฟล์ส่วนหัวและไลบรารีที่คอมไพล์แล้วใน "sysroot" ใน toolchain แบบสแตนด์อโลนของเรา
เริ่มต้นด้วย libjansson
:
git clone https://github.com/akheron/jansson && cd jansson
# Configuration file which we don't use, we may leave it empty
touch src/jansson_private_config.h
sed -i 's/BUILD_SHARED_LIBRARY/BUILD_STATIC_LIBRARY/g' Android.mk
$NDK/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk
cp obj/local/armeabi/libjansson.a $TOOLCHAIN/sysroot/usr/lib/
cp src/jansson.h android/jansson_config.h $TOOLCHAIN/sysroot/usr/include/
cd .. && rm -rf jansson
ตอนนี้เรามาจัดการกับ libpcap
:
git clone https://github.com/the-tcpdump-group/libpcap && cd libpcap
export CC=$TOOLCHAIN/bin/arm-linux-androideabi-gcc
./configure --host=arm-linux --with-pcap=linux --prefix=/usr
# You will need to install some missing dependencies (e.g. `flex` & `bison`)
sudo apt-get install flex bison
# Reissue ./configure untill all dependencies are met
./configure --host=arm-linux --with-pcap=linux --prefix=/usr
# Compile && install in toolchain
make && sudo make install DESTDIR=$TOOLCHAIN/sysroot
cd .. && rm -rf libpcap
ตอนนี้เราพร้อมที่จะคอมไพล์ tcpsnitch
:
# First, let's fix the buggy `tcp.h` header from the NDK
sed -i 's/include <linux/tcp.h>/include <sys/cdefs.h>n#include <linux/tcp.h>/g' $TOOLCHAIN/sysroot/usr/include/netinet/tcp.h
# Configure the compiler
export CC_ANDROID=$TOOLCHAIN/bin/arm-linux-androideabi-gcc
# Build & install tcpsnitch
make android && sudo make install
คุณพร้อมที่จะไปแล้ว! ดูส่วนการใช้งาน Android สำหรับวิธีเริ่มการติดตามแอปพลิเคชัน
คุณลักษณะที่น่าสนใจของไดนามิกลิงเกอร์ Linux ( ld.so
) คือความสามารถในการลิงก์ไลบรารีที่แบ่งใช้ที่ผู้ใช้ระบุก่อนไลบรารีที่ระบุในรายการการขึ้นต่อกันของโปรแกรม คุณลักษณะนี้สามารถควบคุมได้ด้วยตัวแปรสภาพแวดล้อม LD_PRELOAD
ซึ่งมีรายการ (อาจว่างเปล่า) ของไลบรารีเพิ่มเติมที่ผู้ใช้ระบุ โดยเฉพาะอย่างยิ่ง ตัวแปร LD_PRELOAD
นี้อาจบังคับให้ตัวเชื่อมโยงแบบไดนามิกเชื่อมโยงไลบรารีที่แบ่งใช้ที่ผู้ใช้ระบุก่อนไลบรารี libc
ด้วยเหตุนี้ ฟังก์ชันใดๆ ที่กำหนดไว้ในไลบรารีที่ผู้ใช้ระบุนี้จะมีความสำคัญเหนือกว่าฟังก์ชันที่มีลายเซ็นเดียวกันซึ่งกำหนดไว้ใน libc
ความหมายโดยนัยที่นี่คืออนุญาตให้ดักฟังการโทรไปยังฟังก์ชัน wrapper การโทรของระบบ เราเพียงแค่ต้องเพิ่มไลบรารีที่ใช้ร่วมกันที่กำหนดเองซึ่งกำหนดฟังก์ชัน wrapper การเรียกของระบบเหล่านี้ใหม่เป็น LD_PRELOAD
จากนั้นไลบรารี shim ดังกล่าวจะสกัดกั้นการเรียกฟังก์ชัน libc
อย่างโปร่งใส และดำเนินการประมวลผลบางอย่างก่อนที่จะเรียกใช้ฟังก์ชัน libc
wrapper ดั้งเดิม
wrong ELF class
เหล่านี้คืออะไร ไม่มีอะไรเลวร้าย สิ่งเหล่านี้สามารถละเลยได้ ไลบรารีที่ใช้ร่วมกัน tcpsnitch
ได้รับการคอมไพล์สำหรับสถาปัตยกรรมทั้ง 32 บิตและ 64 บิต เมื่อติดตามคำสั่ง ไลบรารีทั้งสองจะถูกโหลดในตัวแปรสภาพแวดล้อม LD_PRELOAD
เนื่องจากไม่มีวิธีง่ายๆ ในการทราบสถาปัตยกรรมของไบนารีคำสั่ง (โดยมากจะเป็นเชลล์สคริปต์ที่เรียกใช้ไบนารีอื่น) จากนั้นตัวเชื่อมโยงแบบไดนามิกจะดูแลการโหลดไลบรารีที่เข้ากันได้และละเว้นอันที่สอง (แต่ยังคงแสดงข้อผิดพลาด)
มาพูดคุยเกี่ยวกับ tcpsnitch
ได้ที่ https://gitter.im/Tcpsnitch
อีเมลของผู้เขียนคือ gregory.vanderschueren[at]gmail.com