สำหรับโปรเจ็กต์นี้ ฉันย้อนกลับวิศวกรรมแอป "C by GE" เพื่อควบคุมหลอดไฟอัจฉริยะที่เชื่อมต่อ GE ที่เชื่อมต่อ WiFi ในการทำเช่นนี้ ฉันเริ่มต้นด้วยการถอดรหัสแอป Android จากนั้นทำวิศวกรรมย้อนกลับกับโปรโตคอลไบนารี่ที่แอปใช้เพื่อสื่อสารกับเซิร์ฟเวอร์ สำหรับรายละเอียดเพิ่มเติม โปรดดู Reverse Engineering C โดย GE
ผลิตภัณฑ์สุดท้ายของโครงการนี้คือ:
ข้อจำกัดความรับผิดชอบ: รหัสนี้เป็นผลมาจากวิศวกรรมย้อนกลับและไม่ได้รับแจ้งจากข้อกำหนดของโปรโตคอล ด้วยเหตุนี้จึงไม่รับประกันว่าจะใช้งานได้ต่อไปหรือจะใช้ได้กับทุกเครือข่ายหรืออุปกรณ์อัจฉริยะ แม้ว่าบางกรณีจะใช้ API นี้สำเร็จ แต่ก็เป็นไปได้ที่โค้ดจะตั้งสมมติฐานที่ไม่ถูกต้องซึ่งไม่ได้รองรับทุกกรณีการใช้งาน
ไดเร็กทอรีเซิร์ฟเวอร์เป็นเว็บแอปในตัวเองและจุดสิ้นสุด JSON API สำหรับหลอดไฟ C by GE เว็บไซต์มีลักษณะดังนี้:
หากคุณใช้งานเว็บไซต์ด้วยอาร์กิวเมนต์ -email
และ -password
เว็บไซต์จะแสดงหน้าการตรวจสอบสิทธิ์แบบสองปัจจัยในครั้งแรกที่คุณโหลด คุณจะกดปุ่มและป้อนรหัสยืนยันที่ส่งไปยังอีเมลของคุณ หรือคุณสามารถเข้าสู่ระบบล่วงหน้าได้ด้วยการรันคำสั่ง login_2fa โดยมีแฟล็ก -email
และ -password
ตั้งค่าเป็นข้อมูลบัญชีของคุณ คำสั่งจะแจ้งให้คุณใส่รหัสยืนยัน 2FA เมื่อคุณป้อนรหัสนี้ คำสั่งจะพ่นข้อมูลเซสชันออกมาเป็น JSON blob จากนั้นคุณสามารถส่ง JSON นี้ไปยังอาร์กิวเมนต์ -sessinfo
ของเซิร์ฟเวอร์ เช่น -sessinfo 'JSON HERE'
โปรดทราบว่าส่วนหนึ่งของเซสชันจะหมดอายุหลังจากผ่านไปหนึ่งสัปดาห์ แต่อินสแตนซ์เซิร์ฟเวอร์ที่ทำงานอยู่จะยังคงทำงานต่อหลังจากเวลานี้ เนื่องจากส่วนที่หมดอายุของเซสชันจะใช้เพียงครั้งเดียวเพื่อระบุอุปกรณ์
บัญชีที่ใหม่กว่าจำเป็นต้องใช้การรับรองความถูกต้องด้วยสองปัจจัย คุณสามารถทำการจับมือ 2FA เพื่อสร้างเซสชันได้ดังนี้:
callback , err := cbyge . Login2FA ( "my_email" , "my_password" , "" )
// Handle error...
sessionInfo , err := callback ( "2FA code from email" )
// Handle error...
session , err := cbyge . NewController ( sessionInfo , 0 )
// Handle error...
สำหรับบัญชีเก่าที่ไม่เคยใช้ 2FA มาก่อน คุณสามารถเข้าสู่ระบบได้โดยตรง:
session , err := cbyge . NewControllerLogin ( "my_email" , "my_password" )
// Handle error...
เมื่อคุณมีเซสชันแล้ว คุณสามารถระบุอุปกรณ์ได้ดังนี้:
devs , err := session . Devices ()
// Handle error...
for _ , x := range devs {
fmt . Println ( x . Name ())
}
คุณสามารถควบคุมหลอดไฟได้ดังนี้:
x := devs [ 0 ]
session . SetDeviceStatus ( x , true ) // turn on
session . SetDeviceLum ( x , 50 ) // set brightness
session . SetDeviceCT ( x , 100 ) // set color tone (100=blue, 0=orange)
คุณยังสามารถสอบถามการตั้งค่าปัจจุบันของหลอดไฟได้:
status , err := session . DeviceStatus ( x )
// Handle error...
fmt . Println ( status . IsOn )
fmt . Println ( status . ColorTone )
ในส่วนนี้ ฉันจะอธิบายวิธีที่ฉันวิศวกรรมย้อนกลับส่วนต่างๆ ของโปรโตคอล C by GE
ขั้นตอนแรกคือการแยกส่วนแอป Android ด้วย Apktool สิ่งนี้ทำให้เกิดการแยกส่วน Smali สำหรับแอป ฉันลองค้นหา URL และชื่อโดเมน ตอนแรกฉันพบสิ่งนี้:
.field public static final API_VERSION : L java/lang/String ; = " v2/ "
.field public static final BASE_URL : L java/lang/String ; = " https://api-ge.xlink.cn:443/ "
การได้เห็นว่าตำแหน่งข้อมูล API นี้ถูกใช้ไปที่ใดอย่างรวดเร็วทำให้ฉันพบชุดการเรียก HTTP ที่ใช้ JSON สำหรับการเข้าสู่ระบบ รายการอุปกรณ์ ฯลฯ อย่างไรก็ตาม ตำแหน่งข้อมูลนี้ดูเหมือนจะไม่มีวิธี 1) รับสถานะของอุปกรณ์ หรือ 2) อัพเดตสีหรือความสว่างของอุปกรณ์
ต้องมีวิธีอื่นที่แอปสื่อสารกับหลอดไฟอัจฉริยะ อย่างไรก็ตาม การถอดแยกชิ้นส่วนเต็มไปด้วยโค้ดสำหรับการสื่อสาร Bluetooth และ LAN และฉันก็กังวลเล็กน้อยว่า ไม่มี จุดสิ้นสุด API ส่วนกลางสำหรับการควบคุมหลอดไฟ ที่แย่กว่านั้นคือแอป C by GE จะบ่นทุกครั้งที่ฉันปิดบลูทูธแล้วลองใช้งาน อย่างไรก็ตาม ในที่สุดฉันก็พบว่าฉันสามารถเปิดแอป ปล่อยให้มันทำหน้าที่ของมัน จากนั้นปิดบลูทูธและ WiFi ในขณะที่ยังคงควบคุมหลอดไฟได้ สิ่งที่ฉันต้องทำคือกดปุ่ม "ย้อนกลับ" ของ Android ทุกครั้งที่แอปเปิดป๊อปอัปเพื่อขอให้ฉัน "เปิดการติดตามตำแหน่ง" (ชื่อแปลก ๆ สำหรับ Bluetooth และ WiFi นะ)
เมื่อมาถึงจุดนี้ ฉันค่อนข้างแน่ใจว่าแอปไม่ได้ทำการเชื่อมต่อ HTTP(S) ลึกลับอื่นๆ ที่น่าสนใจคือ ฉันพบโดเมน "xlink.cn" ที่อื่นในโค้ด Smali:
.field public static final CM_SERVER_ADDRESS : L java/lang/String ; = " cm-ge.xlink.cn "
.field public static final CM_SERVER_PORT : I = 0x5ce2
วัวศักดิ์สิทธิ์ นี่อาจเป็นโปรโตคอลที่ใช้ซ็อกเก็ตแบบดิบหรือไม่ ฉันพยายามแล้วและแน่นอนว่าฉันสามารถเปิดการเชื่อมต่อ TCP ไปที่ cm-ge.xlink.cn:23778
ได้ อย่างไรก็ตาม Smali ยังเต็มไปด้วยตรรกะสำหรับแพ็กเก็ต UDP ดังนั้นฉันจึงไม่แน่ใจว่าแอปจะใช้โปรโตคอลใด ด้วยเหตุนี้ ฉันจึงสร้าง packet-proxy และตั้งค่าให้ฟังบนพอร์ต 23778 จากนั้นฉันก็แทนที่โดเมน cm-ge.xlink.cn
ด้วยที่อยู่ IP ของฉันในโค้ด Smali คอมไพล์แอปใหม่เป็น APK และติดตั้งบน โทรศัพท์ของฉัน
แน่นอนว่าแอป C by GE ที่ได้รับแพตช์ของฉันเชื่อมต่อกับอินสแตนซ์แพ็คเก็ตพร็อกซีของฉันทันทีและเริ่มพูดคุยกัน โดยเฉพาะอย่างยิ่งมันจะเกิดขึ้นเฉพาะเมื่อปิด Bluetooth และ WiFi เท่านั้น มิฉะนั้นดูเหมือนว่าจะชอบหนึ่งในนั้นสำหรับการสื่อสารกับหลอดไฟอัจฉริยะในท้องถิ่น
โปรโตคอลที่แอปเลือกใช้นั้นเป็นผลลัพธ์ที่ง่ายที่สุดในการจัดการ: 1) เป็น TCP แทนที่จะเป็น UDP 2) ไม่มีการเข้ารหัสโดยสมบูรณ์ การขาดการเข้ารหัสค่อนข้างน่าตกใจเมื่อมองย้อนกลับไป เนื่องจากข้อความแรกมีโทเค็นการอนุญาตซึ่งดูเหมือนว่าจะไม่มีการเปลี่ยนแปลงสำหรับบัญชีของฉัน
ฉันพบว่าข้อความจากแอปไปยังเซิร์ฟเวอร์สามารถ "เล่นซ้ำ" ได้อย่างมีประสิทธิภาพ เมื่อฉันรู้ว่าไบต์ใด (หรือ "แพ็กเก็ต" ต้องขอบคุณ packet-proxy) ที่ใช้เปิดและปิดไฟ ฉันสามารถเปิดซ็อกเก็ตใหม่และส่งแพ็กเก็ตเดียวกันเหล่านี้และรับผลลัพธ์เดียวกัน นี่เป็นสัญญาณที่ดี กรณีที่เลวร้ายที่สุด ฉันมีวิธีนำสิ่งที่ฉันต้องการไปปรับใช้กับตัวเองแล้ว แม้ว่าจะไม่เป็นเรื่องทั่วไปก็ตาม
เมื่อถึงจุดนี้ ถึงเวลาที่จะเจาะลึกลงไปในโปรโตคอลแล้ว หลังจากการทดลองกับ packet-proxy และการเจาะลึกการแยกส่วน Smali เข้าด้วยกัน ฉันมีความเข้าใจโดยทั่วไปว่าการสื่อสารเกิดขึ้นอย่างไร สิ่งแรกที่ฉันสังเกตเห็นคือการสื่อสารเกิดขึ้นใน "ข้อความ" ซึ่งเริ่มต้นด้วยประเภทและฟิลด์ความยาว (ใน big endian) สิ่งต่อไปคือการหาว่าแพ็กเก็ตประเภทใดอยู่ที่ไหน และในที่สุดแพ็กเก็ตเฉพาะนั้นถูกเข้ารหัสอย่างไร นี่คือตัวอย่างของแพ็กเก็ตจากเซิร์ฟเวอร์ที่มีสถานะของอุปกรณ์ทั้งสามของฉัน:
73 00 00 00 60 47 e2 be ab 00 37 00 7e 00 01 00 00 f9 52 4e
00 03 00 00 00 03 00 03 00 81 01 00 00 81 01 00 00 00 00 35
00 00 00 27 00 00 00 00 00 00 00 02 00 00 01 00 00 00 01 00
00 00 00 35 00 00 00 27 00 00 00 00 00 00 00 01 00 00 01 00
00 00 01 00 00 00 00 35 00 00 00 27 00 00 00 00 00 00 00 c8
7e
เมื่อฉันจัดการโปรโตคอลได้เพียงพอแล้ว ฉันจึงสร้าง API สำหรับมันขึ้นมา API นี้สามารถแสดงรายการอุปกรณ์ รับสถานะ และอัปเดตคุณสมบัติต่างๆ ของอุปกรณ์ (เช่น ความสว่างและโทนสี) น่าแปลกที่ฉันพบว่า API ของฉันเร็วกว่าและเชื่อถือได้มากกว่าตัวแอปมาก ดูเหมือนว่าการพยายามใช้บลูทูธหรือ WiFi ก่อนที่จะถอยกลับไปยังเซิร์ฟเวอร์ระยะไกลจะทำให้แอปมีความไม่สม่ำเสมอและเชื่อถือได้น้อยกว่าที่ควรจะเป็น
สุดท้ายนี้ ฉันไม่ได้เป็นเจ้าของอุปกรณ์ทั้งหมดที่แอปนี้รองรับ ดังนั้นฉันจึงไม่มีแรงจูงใจ (หรือสามารถทำได้ง่ายๆ) ที่จะวิศวกรรมย้อนกลับว่าอุปกรณ์เหล่านี้ทำงานอย่างไร ตัวอย่างเช่น บริษัทเดียวกันนี้ผลิตปลั๊กไฟอัจฉริยะ เซ็นเซอร์ และสวิตช์ไฟ