การอัปเดต 2020.1.14 ไม่จำเป็นต้องติดตั้งการเจลเบรค
บทความนี้เป็นบทช่วยสอนเกี่ยวกับการกลับไฟล์ไบนารี่ของ WeChat เพื่อทราบถึงการส่งต่อวิดีโอสั้น ๆ ใน Moments ตั้งแต่โค้ดแอสเซมบลีเริ่มต้นไปจนถึงการติดตั้งการลงนามใหม่ครั้งสุดท้ายและการดำเนินการอื่น ๆ บทความนี้จะสอนคุณทีละขั้นตอนถึงวิธีการเล่นกับ WeChat! หลังจากที่คุณเรียนรู้แล้ว มันจะเป็นเรื่องง่ายที่จะย้อนรอยฟังก์ชัน WeChat อื่นๆ
บทความนี้แบ่งออกเป็นสองส่วนเนื่องจากความยาว ส่วนแรก จะอธิบายการทำงานแบบย้อนกลับ นั่นคือ วิธีค้นหาฟังก์ชันที่เกี่ยวข้องและวิธีการนำไปใช้ ส่วนที่สอง จะอธิบายวิธีการติดตั้งลายเซ็นอีกครั้งบนเครื่องที่ไม่ได้เจลเบรค และ ปรับแต่งการติดตั้งบนเครื่องเจลเบรค
ส่วนที่สองของข้อความยังมีรหัสสำหรับ WeChat เพื่อคว้าอั่งเปาโดยอัตโนมัติและแก้ไขจำนวนขั้นตอนของ WeChat สามารถดูได้ทีละขั้นตอนโดยทำตามขั้นตอนของบทความนี้และจะไม่ทำซ้ำที่นี่
ก่อนฝึกซ้อมคุณต้องเตรียมโทรศัพท์มือถือที่ผ่านการเจลเบรคแล้วจึงติดตั้งเครื่องมือทั้งหมดตามรายการด้านล่าง IDA และ Reveal เป็นเวอร์ชันแคร็กทั้งคู่ IDA ของแท้มีราคามากกว่า 2,000 ดอลลาร์ ถือว่าคุ้มค่ากับเงินที่เสียไปสำหรับเครื่องมือวิศวกรรมย้อนกลับที่ยอดเยี่ยมเช่นนี้ อย่างไรก็ตาม หากคุณไม่ใช่บริษัทที่เชี่ยวชาญด้านวิศวกรรมย้อนกลับ ต้องใช้เวอร์ชั่นของแท้ครับ Windows เวอร์ชั่นที่ถอดรหัสแล้วก็โอเคนะครับ ผมยังหาบน Mac ไม่ได้ครับ คุณสามารถใช้ฮอปเปอร์เพื่อแทนที่ IDA บน Mac ซึ่งเป็นเครื่องมือวิศวกรรมย้อนกลับที่ทรงพลังมากเช่นกัน โดยไม่ต้องกังวลใจอีกต่อไป มาเริ่มกันเลย!
หมายเหตุ: ไฟล์ไบนารี WeChat ที่กลับรายการในบทความนี้คือเวอร์ชัน 6.3.28 หากเป็น WeChat เวอร์ชันอื่น ที่อยู่ฐานในไฟล์ไบนารี่ก็จะแตกต่างออกไปด้วย
สภาพแวดล้อมแบบย้อนกลับสำหรับเครื่องเจลเบรค MacOS + iPhone5S 9.1 <br> ขั้นแรกให้ใช้ dumpdecrypted เพื่อทุบเปลือกของ WeChat (หากคุณไม่ทราบวิธี โปรดอ่านบทช่วยสอนนี้ที่เขียนโดยฉัน) รับไฟล์ WeChat.decrypted และขั้นแรกให้โยนไฟล์นี้ไปที่ IDA เพื่อการวิเคราะห์ (ไฟล์ไบนารี่ขนาดประมาณ 60MB IDA ใช้เวลาประมาณ 40 นาทีในการวิเคราะห์ End) ใช้ class-dump เพื่อส่งออกไฟล์ส่วนหัวทั้งหมด
LeonLei-MBP:~ gaoshilei$ class-dump -S -s -H /Users/gaoshilei/Desktop/reverse/binary_for_class-dump/WeChat.decrypted -o /Users/gaoshilei/Desktop/reverse/binary_for_class-dump/class-Header/WeChat
ฉันมีแม่สามี! มีไฟล์ส่วนหัวทั้งหมด 8,000 ไฟล์ และ WeChat มีงานจำนวนมากจริงๆ! สงบอารมณ์ รวบรวมความคิดและดำเนินการต่อ หากต้องการรับลิงก์ดาวน์โหลดวิดีโอสั้น ให้ค้นหามุมมองที่เล่นวิดีโอ และปฏิบัติตามคำแนะนำเพื่อค้นหา URL ของวิดีโอสั้น ใช้ Reveal เพื่อดูหน้าต่างการเล่นของวิดีโอสั้น คุณจะเห็นว่าออบเจ็กต์ WCContentItemViewTemplateNewSigh เป็นหน้าต่างการเล่นของวิดีโอสั้น ๆ รวมถึง WCSightView, SightView และ SightPlayerView คลาสเหล่านี้เป็นจุดเริ่มต้นของเรา เมื่อบันทึกวิดีโอเป็นรายการโปรด ให้กดวิดีโอค้างไว้เพื่อแสดงตัวเลือก ดังนั้นอาจมีวิธีการที่เกี่ยวข้องกับท่าทางในคลาส WCContentItemViewTemplateNewSight ค้นหาเบาะแสในไฟล์ส่วนหัวที่เพิ่งส่งออก
- (void)onLongTouch;
- (void)onLongPressedWCSight:(id)arg1;
- (void)onLongPressedWCSightFullScreenWindow:(id)arg1;
วิธีการเหล่านี้เกี่ยวข้องกับการกดแบบยาว ค้นหาฟังก์ชันเหล่านี้ใน IDA และดูทีละรายการ onLongPressedWCSight และ onLongPressedWCSightFullScreenWindow นั้นค่อนข้างง่าย onLongTouch นั้นค่อนข้างยาว และฉันพบว่าเมธอด Favorites_Add ถูกเรียกภายใน เพราะเมื่อคุณกดวิดีโอค้างไว้ ตัวเลือกที่ออกมาคือรายการโปรด และฉันเห็นการเรียกใช้ฟังก์ชันนี้
ADRP X8, #selRef_sightVideoPath@PAGE
LDR X1, [X8,#selRef_sightVideoPath@PAGEOFF]
ฉันได้รับที่อยู่ของวิดีโอสั้น ๆ ที่นี่ สามารถคาดเดาได้ว่าฟังก์ชันนี้เกี่ยวข้องกับคอลเลกชัน เรามาแยกประเด็นและทดสอบกัน
(lldb) im li -o -f
[ 0] 0x000000000003c000 /var/mobile/Containers/Bundle/Application/2F1D52EC-C57E-4F95-B715-EF04351232E8/WeChat.app/WeChat(0x000000010003c000)
คุณจะเห็นว่า ASLR ของ WeChat คือ 0x3c000 ค้นหาที่อยู่พื้นฐานของฟังก์ชันทั้งสามนี้ใน IDA และตั้งค่าเบรกพอยต์ตามลำดับ
(lldb) br s -a 0x1020D3A10+0x3c000
Breakpoint 1: where = WeChat`___lldb_unnamed_symbol110094$$WeChat + 28, address = 0x000000010210fa10
(lldb) br s -a 0x1020D3370+0x3c000
Breakpoint 2: where = WeChat`___lldb_unnamed_symbol110091$$WeChat + 8, address = 0x000000010210f370
(lldb) br s -a 0x1020D33E4+0x3c000
Breakpoint 3: where = WeChat`___lldb_unnamed_symbol110092$$WeChat + 12, address = 0x000000010210f3e4
กลับไปที่ WeChat แล้วกดวิดีโอสั้นค้างไว้เพื่อดูว่าเบรกพอยต์ทำงานอย่างไร
Process 3721 stopped
* thread #1: tid = 0x658fc, 0x000000010210f370 WeChat`___lldb_unnamed_symbol110091$$WeChat + 8, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
frame #0: 0x000000010210f370 WeChat`___lldb_unnamed_symbol110091$$WeChat + 8
WeChat`___lldb_unnamed_symbol110091$$WeChat:
-> 0x10210f370 <+8>: add x29, sp, #16 ; =16
0x10210f374 <+12>: mov x19, x0
0x10210f378 <+16>: adrp x8, 4968
0x10210f37c <+20>: ldr x0, [x8, #744]
(lldb) c
Process 3721 resuming
Process 3721 stopped
* thread #1: tid = 0x658fc, 0x000000010210fa10 WeChat`___lldb_unnamed_symbol110094$$WeChat + 28, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x000000010210fa10 WeChat`___lldb_unnamed_symbol110094$$WeChat + 28
WeChat`___lldb_unnamed_symbol110094$$WeChat:
-> 0x10210fa10 <+28>: add x29, sp, #96 ; =96
0x10210fa14 <+32>: sub sp, sp, #96 ; =96
0x10210fa18 <+36>: mov x19, x0
0x10210fa1c <+40>: adrp x8, 4863
……
พบว่าเบรกพอยต์ 2 ถูกทริกเกอร์ก่อน จากนั้นเบรกพอยต์ 1 ถูกทริกเกอร์ จากนั้นเบรกพอยต์ 2 และ 1 จะถูกทริกเกอร์ทีละครั้ง คุณสามารถยกเว้นการเชื่อมต่อระหว่าง onLongPressedWCSightFullScreenWindow และคอลเลกชันวิดีโอสั้นได้ จะต้องพบร่องรอยของวิดีโอสั้น ๆ ในสองวิธีที่เหลือ ค้นหา C ถึง V และค้นหา M โดยทำตามเบาะแสที่ได้รับการลองและทดสอบแล้ว! ใช้ไซคริปต์เพื่อแทรก WeChat และรับคอนโทรลเลอร์ในตำแหน่งที่มุมมองที่เล่นวิดีโอสั้นอยู่
cy# [#0x138c18030 nextResponder]
#"<WCTimeLineCellView: 0x138c34620; frame = (0 0; 319 249); tag = 1048577; layer = <CALayer: 0x138362ba0>>"
cy# [#0x138c34620 nextResponder]
#"<UITableViewCellContentView: 0x138223c70; frame = (0 0; 320 256); gestureRecognizers = <NSArray: 0x1384ec480>; layer = <CALayer: 0x138081dc0>>"
cy# [#0x138223c70 nextResponder]
#"<MMTableViewCell: 0x138c9f930; baseClass = UITableViewCell; frame = (0 307; 320 256); autoresize = W; layer = <CALayer: 0x1382dcd10>>"
cy# [#0x138c9f930 nextResponder]
#"<UITableViewWrapperView: 0x137b57800; frame = (0 0; 320 504); gestureRecognizers = <NSArray: 0x1383db660>; layer = <CALayer: 0x138af20c0>; contentOffset: {0, 0}; contentSize: {320, 504}>"
cy# [#0x137b57800 nextResponder]
#"<MMTableView: 0x137b8ae00; baseClass = UITableView; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x138adb590>; layer = <CALayer: 0x138956890>; contentOffset: {0, 99.5}; contentSize: {320, 3193}>"
cy# [#0x137b8ae00 nextResponder]
#"<UIView: 0x138ade5c0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x138ac9990>>"
cy# [#0x138ade5c0 nextResponder]
#"<WCTimeLineViewController: 0x1379eb000>"
ค้นหาตัวควบคุมที่มี WCContentItemViewTemplateNewSight อยู่ผ่านห่วงโซ่การตอบกลับ และเป็น WCTimeLineViewController ไม่พบเบาะแสอันมีค่าในไฟล์ส่วนหัวของคลาสนี้ แต่เราสังเกตเห็นว่ามุมมองที่มีวิดีโอสั้นอยู่นั้นเป็นของ MMTableVIewCell (ดูแผนภูมิการวิเคราะห์เปิดเผยด้านบน) ซึ่งเป็น TableView และข้อมูลเซลล์ที่คุ้นเคยมากที่สุดสำหรับ iOS ทุกเครื่อง ถูกกำหนดผ่านวิธีพร็อกซีของ UITableViewDataSource - tableView:cellForRowAtIndexPath:
ด้วยวิธีนี้ คุณสามารถรู้เงาของ M ได้อย่างแน่นอน ค้นหา [WCTimeLineViewController tableView:cellForRowAtIndexPath:]
ใน IDA และค้นหาที่อยู่ฐาน 0x10128B6B0:
__text:000000010128B6B0 ADRP X8, #selRef_genNormalCell_indexPath_@PAGE
ฟังก์ชันที่นี่คือวิธีการสร้างเซลล์ใน WCTimeLineViewController นอกเหนือจากวิธีนี้แล้ว ยังมีวิธีอื่นอีกสามวิธีในการสร้างเซลล์ในคลาสนี้:
- (void)genABTestTipCell:(id)arg1 indexPath:(id)arg2;
- (void)genRedHeartCell:(id)arg1 indexPath:(id)arg2;
- (void)genUploadFailCell:(id)arg1 indexPath:(id)arg2;
จากความหมายที่แท้จริงเราสามารถเดาได้ว่าปกติควรเป็นวิธีการสร้างเซลล์วิดีโอขนาดเล็ก มองหาเบาะแสใน IDA ต่อไป
__text:0000000101287CC8 ADRP X8, #selRef_getTimelineDataItemOfIndex_@PAGE
วิธีการข้างต้นมีอยู่ในวิธี genNormalCell:IndexPath:
คุณสามารถเดาได้อย่างกล้าหาญว่าวิธีการนี้เป็นวิธีการรับข้อมูลไทม์ไลน์ (ช่วงเวลา) ต้องได้รับข้อมูลของวิดีโอสั้นผ่านวิธีนี้ด้วย และ IDA ก็สามารถเห็นได้ โทรในวิธีนี้ วิธีการที่เรียกว่า selRef_getTimelineDataItemOfIndex_
การได้รับ DataItem ดูเหมือนจะเป็นแหล่งข้อมูลของเซลล์! จากนั้นใช้ LLDB เพื่อตั้งค่าเบรกพอยต์เพื่อตรวจสอบการคาดเดา คุณสามารถค้นหาที่อยู่ฐานที่สอดคล้องกับวิธีนี้ได้ผ่าน IDA: 0x101287CE4 ขั้นแรก ให้พิมพ์ออฟเซ็ต ASLR ของการรัน WeChat
LeonLei-MBP:~ gaoshilei$ lldb
(lldb) process connect connect://localhost:1234
(lldb) im li -o -f
[0] 0x0000000000050000 /var/mobile/Containers/Bundle/Application/2DCE8F30-9B6B-4652-901C-37EB1FF2A40D/WeChat.app/WeChat(0x0000000100050000)
ดังนั้นตำแหน่งของเบรกพอยต์ของเราคือ 0x50000+0x101287CE4
(lldb) br s -a 0x50000+0x101287CE4
Breakpoint 1: where = WeChat`___lldb_unnamed_symbol63721$$WeChat + 252, address = 0x00000001012d7ce4
พิมพ์ค่า x0
(lldb) po $x0
Class name: WCDataItem, addr: 0x15f5f03b0
tid: 12393001887435993280
username: wxid_z8twcz4o18fg12
createtime: 1477360950
commentUsers: (
)
contentObj: <WCContentItem: 0x15f57d000>
รับวัตถุ WCDataItem ค่าของ x0 ในที่นี้คือค่าตอบแทนหลังจากการดำเนินการของ selRef_getTimelineDataItemOfIndex_
แล้วเปลี่ยนค่าของ x0
(lldb) register write $x0 0
(lldb) c
ในเวลานี้ คุณจะพบว่าเนื้อหาของวิดีโอขนาดเล็กที่เราต้องการรีเฟรชนั้นว่างเปล่าทั้งหมด
ณ จุดนี้ เราพบวิธีการรับข้อมูลต้นฉบับของวิดีโอสั้นแล้ว คำถามคือ เราจะรับ WCDataItem นี้ได้อย่างไร ดูสถานะการโทรของฟังก์ชันวิเคราะห์ IDA ต่อไป:
WCTimeLineViewController - (เป็นโมฆะ) genNormalCell: (id) indexPath: (id)
__text:0000000101287BCC STP X28, X27, [SP,#var_60]!
__text:0000000101287BD0 STP X26, X25, [SP,#0x60+var_50]
__text:0000000101287BD4 STP X24, X23, [SP,#0x60+var_40]
__text:0000000101287BD8 STP X22, X21, [SP,#0x60+var_30]
__text:0000000101287BDC STP X20, X19, [SP,#0x60+var_20]
__text:0000000101287BE0 STP X29, X30, [SP,#0x60+var_10]
__text:0000000101287BE4 ADD X29, SP, #0x60+var_10
__text:0000000101287BE8 SUB SP, SP, #0x80
__text:0000000101287BEC MOV X19, X3
__text:0000000101287BF0 MOV X22, X0
__text:0000000101287BF4 MOV W25, #0x100000
__text:0000000101287BF8 MOVK W25, #1
__text:0000000101287BFC MOV X0, X2
__text:0000000101287C00 BL _objc_retain
__text:0000000101287C04 MOV X28, X0
__text:0000000101287C08 MOV X0, X19
__text:0000000101287C0C BL _objc_retain
__text:0000000101287C10 MOV X20, X0
__text:0000000101287C14 STR X20, [SP,#0xE0+var_98]
__text:0000000101287C18 ADRP X8, #selRef_row@PAGE
__text:0000000101287C1C LDR X1, [X8,#selRef_row@PAGEOFF]
__text:0000000101287C20 BL _objc_msgSend
__text:0000000101287C24 MOV X26, X0
__text:0000000101287C28 ADRP X8, #selRef_section@PAGE
__text:0000000101287C2C LDR X19, [X8,#selRef_section@PAGEOFF]
__text:0000000101287C30 MOV X0, X20
__text:0000000101287C34 MOV X1, X19
__text:0000000101287C38 BL _objc_msgSend
__text:0000000101287C3C STR X0, [SP,#0xE0+var_A8]
__text:0000000101287C40 MOV X0, X20
__text:0000000101287C44 MOV X1, X19
__text:0000000101287C48 BL _objc_msgSend
__text:0000000101287C4C MOV X2, X0
__text:0000000101287C50 ADRP X8, #selRef_calcDataItemIndex_@PAGE
__text:0000000101287C54 LDR X1, [X8,#selRef_calcDataItemIndex_@PAGEOFF]
__text:0000000101287C58 MOV X0, X22
__text:0000000101287C5C BL _objc_msgSend
__text:0000000101287C60 MOV X21, X0
__text:0000000101287C64 STR X21, [SP,#0xE0+var_C0]
__text:0000000101287C68 ADRP X8, #classRef_MMServiceCenter@PAGE
__text:0000000101287C6C LDR X0, [X8,#classRef_MMServiceCenter@PAGEOFF]
__text:0000000101287C70 ADRP X8, #selRef_defaultCenter@PAGE
__text:0000000101287C74 LDR X1, [X8,#selRef_defaultCenter@PAGEOFF]
__text:0000000101287C78 STR X1, [SP,#0xE0+var_B8]
__text:0000000101287C7C BL _objc_msgSend
__text:0000000101287C80 MOV X29, X29
__text:0000000101287C84 BL _objc_retainAutoreleasedReturnValue
__text:0000000101287C88 MOV X19, X0
__text:0000000101287C8C ADRP X8, #classRef_WCFacade@PAGE
__text:0000000101287C90 LDR X0, [X8,#classRef_WCFacade@PAGEOFF]
__text:0000000101287C94 ADRP X8, #selRef_class@PAGE
__text:0000000101287C98 LDR X1, [X8,#selRef_class@PAGEOFF]
__text:0000000101287C9C STR X1, [SP,#0xE0+var_B0]
__text:0000000101287CA0 BL _objc_msgSend
__text:0000000101287CA4 MOV X2, X0
__text:0000000101287CA8 ADRP X8, #selRef_getService_@PAGE
__text:0000000101287CAC LDR X1, [X8,#selRef_getService_@PAGEOFF]
__text:0000000101287CB0 STR X1, [SP,#0xE0+var_A0]
__text:0000000101287CB4 MOV X0, X19
__text:0000000101287CB8 BL _objc_msgSend
__text:0000000101287CBC MOV X29, X29
__text:0000000101287CC0 BL _objc_retainAutoreleasedReturnValue
__text:0000000101287CC4 MOV X20, X0
__text:0000000101287CC8 ADRP X8, #selRef_getTimelineDataItemOfIndex_@PAGE
__text:0000000101287CCC LDR X1, [X8,#selRef_getTimelineDataItemOfIndex_@PAGEOFF]
__text:0000000101287CD0 STR X1, [SP,#0xE0+var_C8]
__text:0000000101287CD4 MOV X2, X21
__text:0000000101287CD8 BL _objc_msgSend
__text:0000000101287CDC MOV X29, X29
__text:0000000101287CE0 BL _objc_retainAutoreleasedReturnValue
__text:0000000101287CE4 MOV X21, X0
__text:0000000101287CE8 MOV X0, X20
......
พารามิเตอร์ที่ส่งผ่านไปยัง selRef_getTimelineDataItemOfIndex_
คือ x2 คุณจะเห็นว่า x21 ส่งผ่านไปยัง x2 เป็นค่าที่ส่งคืนของฟังก์ชัน selRef_calcDataItemIndex_
ซึ่งเป็นประเภทข้อมูลแบบยาวที่ไม่ได้ลงนาม ดำเนินการวิเคราะห์ต่อไป ผู้เรียกฟังก์ชัน selRef_getTimelineDataItemOfIndex_
คือค่าที่ส่งคืนของ selRef_getService_
ในขั้นตอนก่อนหน้า หลังจากการวิเคราะห์เบรกพอยต์ พบว่าเป็นวัตถุ WCFacade
มาเรียงลำดับการโทรไปที่ selRef_getTimelineDataItemOfIndex_
:
ผู้เรียกคือค่าตอบแทนของ selRef_getService_
พารามิเตอร์คือค่าตอบแทนของ selRef_calcDataItemIndex_
<br> ให้เราหันมาสนใจทั้งสองฟังก์ชันนี้และใช้หลักการเดียวกันเพื่อวิเคราะห์ว่าพวกเขาใช้การโทรอย่างไร
selRef_getService_
ก่อน:MMServiceCenter
เป็นการส่งคืนค่า [MMServiceCenter defaultCenter]
[WCFacade class]
selRef_calcDataItemIndex_
:WCTimeLineViewController
ผู้โทร x0 ที่ตำแหน่ง 0x101287C58selRef_section
0x101287C4C พบว่า selRef_section
ขาเข้ามาจาก selRef_section
หรือเป็น x3WCTimeLineViewController - (void)genNormalCell:(id) indexPath:(id)
ดังนั้นพารามิเตอร์ของ selRef_calcDataItemIndex_
จึงเป็น [IndexPath section]
getTimelineDataItemOfIndex:
สามารถผ่านได้ [[MMServiceCenter defaultCenter] getService:[WCFacade class]]
หากต้องการรับพารามิเตอร์สามารถรับได้ผ่านฟังก์ชันต่อไปนี้
[WCTimeLineViewController calcDataItemIndex:[indexPath section]]
รู้สึกเหมือนมีบางอย่างขาดหายไปอยู่เสมอ? เรายังไม่ได้รับ indexPath! ขั้นตอนต่อไปคือการรับ indexPath ซึ่งค่อนข้างง่าย เนื่องจากเราอยู่ใน [WCContentItemViewTemplateNewSight onLongTouch]
ดังนั้นเราจึงสามารถรับ MMTableViewCell, MMTableView และ WCTimeLineViewController ตามลำดับผ่าน [self nextResponder]
จากนั้นรับ indexPath ผ่าน [MMTableView indexPathForCell:MMTableViewCell]
.
หลังจากทำเช่นนี้ เราได้รับวัตถุ WCDataItem โฟกัสต่อไปควรอยู่ที่ WCDataItem และสุดท้ายก็ได้วิดีโอสั้น ๆ ที่เราต้องการ ค้นหาเบาะแสในไฟล์ส่วนหัวของคลาสนี้ เนื่องจากวิดีโอสามารถเล่นได้หลังจากดาวน์โหลดเท่านั้น จึงควรได้รับเส้นทางของวิดีโอที่นี่ ดังนั้นให้ใส่ใจกับแอตทริบิวต์หรือวิธีการที่เกี่ยวข้องกับ url และเส้นทาง จากนั้นค้นหาสิ่งต่อไปนี้ ผู้ต้องสงสัย
@property(retain, nonatomic) NSString *sourceUrl2;
@property(retain, nonatomic) NSString *sourceUrl;
- (id)descriptionForKeyPaths;
- (id)keyPaths;
กลับไปที่ LLDB และพิมพ์ค่าเหล่านี้พร้อมเบรกพอยต์เพื่อดูว่ามีอะไรอยู่
(lldb) po [$x0 keyPaths]
<__NSArrayI 0x15f74e9d0>(
tid,
username,
createtime,
commentUsers,
contentObj
)
(lldb) po [$x0 descriptionForKeyPaths]
Class name: WCDataItem, addr: 0x15f5f03b0
tid: 12393001887435993280
username: wxid_z8twcz4o18fg12
createtime: 1477360950
commentUsers: (
)
contentObj: <WCContentItem: 0x15f57d000>
(lldb) po [$x0 sourceUrl]
nil
(lldb) po [$x0 sourceUrl2]
nil
ไม่มีเบาะแสอันมีค่า แต่ฉันสังเกตเห็นว่ามี WCContentItem ใน WCDataItem ดูเหมือนว่าวิธีเดียวที่จะเริ่มต้นคือที่นี่ มาดูไฟล์ส่วนหัวกัน
@property(retain, nonatomic) NSString *linkUrl;
@property(retain, nonatomic) NSString *linkUrl2;
@property(retain, nonatomic) NSMutableArray *mediaList;
พิมพ์ออกมาใน LLDB
(lldb) po [[$x0 valueForKey:@"contentObj"] linkUrl]
https://support.weixin.qq.com/cgi-bin/mmsupport-bin/readtemplate?t=page/common_page__upgrade&v=1
(lldb) po [[$x0 valueForKey:@"contentObj"] linkUrl2]
nil
(lldb) po [[$x0 valueForKey:@"contentObj"] mediaList]
<__NSArrayM 0x15f985e10>(
<WCMediaItem: 0x15dfebdf0>
)
มีวัตถุ WCMediaItem ในอาร์เรย์ mediaList โดยทั่วไปแล้วสื่อจะใช้เพื่อแสดงวิดีโอและเสียง ฉันเดาได้เลยว่านี่คือมัน! ค้นหาไฟล์ส่วนหัวอย่างรวดเร็วและค้นหา
@property(retain, nonatomic) WCUrl *dataUrl;
- (id)pathForData;
- (id)pathForSightData;
- (id)pathForTempAttachVideoData;
- (id)videoStreamForData;
ในบรรดาแอตทริบิวต์และวิธีการข้างต้น pathForSightData
มีแนวโน้มมากที่สุดที่จะได้รับเส้นทางวิดีโอแบบสั้น ดำเนินการตรวจสอบต่อไป
(lldb) po [[[[$x0 valueForKey:@"contentObj"] mediaList] lastObject] dataUrl]
type[1], url[http://vweixinf.tc.qq.com/102/20202/snsvideodownload?filekey=30270201010420301e020166040253480410d14adcddf086f4e131d11a5b1cca1bdf0203039fa00400&bizid=1023&hy=SH&fileparam=302c0201010425302302040fde55e20204580ebd3602024eea02031e8d7d02030f42400204d970370a0201000400], enckey[0], encIdx[-1], token[]
(lldb) po [[[[$x0 valueForKey:@"contentObj"] mediaList] lastObject] pathForData]
/var/mobile/Containers/Data/Application/7C3A6322-1F57-49A0-ACDE-6EF0ED74D137/Library/WechatPrivate/6f696a1b596ce2499419d844f90418aa/wc/media/5/53/8fb0cdd77208de5b56169fb3458b45
(lldb) po [[[[$x0 valueForKey:@"contentObj"] mediaList] lastObject] pathForSightData]
/var/mobile/Containers/Data/Application/7C3A6322-1F57-49A0-ACDE-6EF0ED74D137/Library/WechatPrivate/6f696a1b596ce2499419d844f90418aa/wc/media/5/53/8fb0cdd77208de5b56169fb3458b45.mp4
(lldb) po [[[[$x0 valueForKey:@"contentObj"] mediaList] lastObject] pathForAttachVideoData]
nil
(lldb) po [[[[$x0 valueForKey:@"contentObj"] mediaList] lastObject] videoStreamForData]
nil
ได้รับ URL เครือข่ายและเส้นทางในเครื่องของวิดีโอสั้นแล้ว! ที่นี่ คุณสามารถใช้ iFunBox หรือ scp เพื่อคัดลอกไฟล์นี้จากแซนด์บ็อกซ์เพื่อดูว่าเป็นวิดีโอสั้นที่เซลล์นี้ควรเล่นหรือไม่
LeonLei-MBP:~ gaoshilei$ scp [email protected]:/var/mobile/Containers/Data/Application/7C3A6322-1F57-49A0-ACDE-6EF0ED74D137/Library/WechatPrivate/6f696a1b596ce2499419d844f90418aa/wc/media/5/53/8fb0cdd77208de5b56169fb3458b45.mp4 Desktop/
8fb0cdd77208de5b56169fb3458b45.mp4 100% 232KB 231.9KB/s 00:00
เปิดด้วย QuickTime แล้วพบว่าเป็นวิดีโอสั้น ๆ ที่เรากำลังมองหา ตรวจสอบว่า URL ถูกต้องอีกครั้ง เปิด dataUrl ที่พิมพ์ด้านบนในเบราว์เซอร์แล้วพบว่าเป็นวิดีโอสั้นนี้ด้วย การวิเคราะห์คลาสนี้เราสามารถสรุปได้ดังต่อไปนี้:
ณ จุดนี้ การวิเคราะห์เส้นทางและวิธีการได้มาของวิดีโอสั้นเสร็จสมบูรณ์แล้ว เพื่อให้บรรลุการส่งต่อ เราจำเป็นต้องวิเคราะห์การเปิดตัว WeChat Moments ต่อไป
ส่วนนี้เป็นทางเบี่ยงที่ฉันใช้เมื่อมองหาฟังก์ชันการส่งต่อวิดีโอสั้น ๆ ในท้ายที่สุดฉันก็ไม่พบวิธีที่จะนำไปใช้ อย่างไรก็ตาม ยังมีแนวคิดและวิธีการที่ใช้กันทั่วไปในการทำวิศวกรรมย้อนกลับอีกด้วย ไม่อยากอ่านก็ข้ามไปอ่านภาคสองได้เลย
เปิดอินเทอร์เฟซการถ่ายวิดีโอสั้นแล้วใส่ไซคริปต์ เราจำเป็นต้องค้นหาวิธีการเผยแพร่วิดีโอสั้น จากนั้นตรวจสอบว่าหน้าต่างใดอยู่ในหน้าต่างปัจจุบัน (เนื่องจากการถ่ายวิดีโอสั้นไม่เสร็จสิ้น ในหน้าต่างคีย์ของ UIApplication)
cy# [UIApp windows].toString()
(
"<iConsoleWindow: 0x125f75e20; baseClass = UIWindow; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x125f77b70>; layer = <UIWindowLayer: 0x125df4810>>",
"<SvrErrorTipWindow: 0x127414d40; baseClass = UIWindow; frame = (0 64; 320 45); hidden = YES; gestureRecognizers = <NSArray: 0x12740d930>; layer = <UIWindowLayer: 0x1274030b0>>",
"<MMUIWindow: 0x127796440; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x1278083c0>; layer = <UIWindowLayer: 0x127796750>>",
"<UITextEffectsWindow: 0x1270e0d40; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = <UIWindowLayer: 0x1270b4ba0>>",
"<NewYearActionSheet: 0x127797e10; baseClass = UIWindow; frame = (0 0; 320 568); hidden = YES; userInteractionEnabled = NO; layer = <UIWindowLayer: 0x1277d5490>>"
)
พบว่าหน้าปัจจุบันมีทั้งหมด 5 หน้าต่าง โดย MMUIWindow เป็นหน้าต่างที่ใช้ถ่ายวิดีโอสั้น ๆ
cy# [#0x127796440 recursiveDescription]
ผลการพิมพ์ค่อนข้างยาวดังนั้นฉันจึงไม่โพสต์ มองหาปุ่มนี้ซึ่งเป็นปุ่มสำหรับถ่ายวิดีโอสั้น ๆ
| | | | | | <UIButton: 0x1277a9d70; frame = (89.5 368.827; 141 141); opaque = NO; gestureRecognizers = <NSArray: 0x1277aaeb0>; layer = <CALayer: 0x1277a9600>>
| | | | | | | <UIView: 0x1277aa0a0; frame = (0 0; 141 141); userInteractionEnabled = NO; tag = 252707333; layer = <CALayer: 0x1277aa210>>
| | | | | | | | <UIImageView: 0x1277aa2e0; frame = (0 0; 141 141); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1277aa490>>
แล้วดำเนินการ
cy# [#0x1277a9d70 setHidden:YES]
ฉันพบว่าปุ่มถ่ายภาพหายไป ซึ่งยืนยันความสงสัยของฉัน หากต้องการค้นหาเหตุการณ์การตอบสนองของปุ่ม คุณสามารถค้นหาได้จากเป้าหมาย
cy# [#0x1277a9d70 allTargets]
[NSSet setWithArray:@[#"<MainFrameSightViewController: 0x1269a4600>"]]]
cy# [#0x1277a9d70 allControlEvents]
193
cy# [#0x1277a9d70 actionsForTarget:#0x1269a4600 forControlEvent:193]
null
ฉันพบว่าปุ่มไม่มีการทำงานที่สอดคล้องกัน ซึ่งแปลกมาก! UIButton ต้องมีเป้าหมายและการดำเนินการ ไม่เช่นนั้นปุ่มจะไม่สามารถตอบสนองต่อเหตุการณ์ได้ มาลอง ControlEvents อื่น ๆ กัน
cy# [#0x1277a9d70 actionsForTarget:#0x1269a4600 forControlEvent:UIControlEventTouchDown]
@["btnPress"]
cy# [#0x1277a9d70 actionsForTarget:#0x1269a4600 forControlEvent:UIControlEventTouchUpOutside]
@["btnRelease"]
cy# [#0x1277a9d70 actionsForTarget:#0x1269a4600 forControlEvent:UIControlEventTouchUpInside]
@["btnRelease"]
ปรากฎว่า ControlEvents ทั้งสามนี้มีการดำเนินการที่สอดคล้องกัน มาดูค่าของการแจงนับทั้งสามนี้กัน
typedef enum UIControlEvents : NSUInteger {
UIControlEventTouchDown = 1 << 0,
UIControlEventTouchDownRepeat = 1 << 1,
UIControlEventTouchDragInside = 1 << 2,
UIControlEventTouchDragOutside = 1 << 3,
UIControlEventTouchDragEnter = 1 << 4,
UIControlEventTouchDragExit = 1 << 5,
UIControlEventTouchUpInside = 1 << 6,
UIControlEventTouchUpOutside = 1 << 7,
UIControlEventTouchCancel = 1 << 8,
......
} UIControlEvents;
จะเห็นได้ว่า UIControlEventTouchUpOutside สอดคล้องกับ 1, UIControlEventTouchUpInside สอดคล้องกับ 128, UIControlEventTouchUpOutside สอดคล้องกับ 64 และผลรวมของทั้งสามคือ 193 พอดี! ปรากฎว่าเมื่อเรียก [#0x1277a9d70 allControlEvents]
ค่าที่ส่งคืนควรเป็นการแจงนับ หากมีการแจงนับหลายรายการ ให้เพิ่มค่าเหล่านั้นเข้าไป ไม่ทำให้สับสนใช่ไหม ฉันก็รู้สึกแบบเดียวกัน! ตอนนี้เราได้พิมพ์การดำเนินการที่สอดคล้องกับ ControlEvents ทั้งสามรายการ และดำเนินการต่อด้วย LLDB+IDA สำหรับการวิเคราะห์แบบไดนามิก
เนื่องจากเราจำเป็นต้องหาวิธีเผยแพร่วิดีโอสั้น ๆ เราจึงไม่สนใจฟังก์ชัน btnPress
ที่เกี่ยวข้อง เรามุ่งเน้นไปที่ btnRelease
วิธีการที่จะเรียกหลังจากปล่อยปุ่มถ่ายภาพ ค้นหาวิธีนี้ใน IDA และตั้งค่าเบรกพอยต์ถัดไปหลังจากค้นหาแล้ว
(lldb) br s -a 0xac000+0x10209369C
Breakpoint 4: where = WeChat`___lldb_unnamed_symbol108894$$WeChat + 32, address = 0x000000010213f69c
Process 3813 stopped
* thread #1: tid = 0xf1ef0, 0x000000010213f69c WeChat`___lldb_unnamed_symbol108894$$WeChat + 32, queue = 'com.apple.main-thread', stop reason = breakpoint 4.1
frame #0: 0x000000010213f69c WeChat`___lldb_unnamed_symbol108894$$WeChat + 32
WeChat`___lldb_unnamed_symbol108894$$WeChat:
-> 0x10213f69c <+32>: bl 0x1028d0b60 ; symbol stub for: objc_msgSend
0x10213f6a0 <+36>: cmp w0, #2 ; =2
0x10213f6a4 <+40>: b.ne 0x10213f6dc ; <+96>
0x10213f6a8 <+44>: adrp x8, 5489
ถ่ายวิดีโอสั้น ๆ ด้วยโทรศัพท์มือถือของคุณแล้วปล่อยเพื่อกระตุ้นจุดพักซึ่งแสดงว่าการคาดเดาของเราถูกต้อง จากการวิเคราะห์ต่อพบว่าโค้ดนั้นมาจากด้านขวาของภาพด้านบน ดูแล้วไม่มีทางข้ามไปยังวิดีโอที่เผยแพร่ได้ อย่างไรก็ตาม หากสังเกตดีๆ ก็มีบล็อกอยู่ ซึ่งก็คือ บล็อกการหน่วงเวลาของระบบและอยู่ที่ 0x102093760 จากนั้นเราติดตามเบรกพอยต์แล้วข้ามไปยังที่อยู่ที่เก็บไว้ใน x16 ที่ 0x1028255A0
(lldb) si
Process 3873 stopped
* thread #1: tid = 0xf62c4, 0x00000001028d9598 WeChat`dispatch_after, queue = 'com.apple.main-thread', stop reason = instruction step into
frame #0: 0x00000001028d9598 WeChat`dispatch_after
WeChat`dispatch_after:
-> 0x1028d9598 <+0>: adrp x16, 1655
0x1028d959c <+4>: ldr x16, [x16, #1056]
0x1028d95a0 <+8>: br x16
WeChat`dispatch_apply:
0x1028d95a4 <+0>: adrp x16, 1655
(lldb) po $x2
<__NSStackBlock__: 0x16fd49f88>
พบว่าพารามิเตอร์ x2 ที่ส่งผ่านนั้นเป็นบล็อก ลองตรวจสอบฟังก์ชัน Dispatch_after อีกครั้ง
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
ฟังก์ชันนี้มีพารามิเตอร์สามตัว ได้แก่ Dispatch_time_t, Dispatch_queue_t และ Dispatch_block_t x2 ที่พิมพ์ไว้ที่นี่คือบล็อกที่จะส่งผ่าน ดังนั้นเราเดาว่าจะมีความล่าช้าหลังจากถ่ายวิดีโอสั้น ๆ จากนั้นจึงดำเนินการบล็อกที่เพิ่งส่งผ่านเข้าไป ดังนั้น x2 จะต้องเป็น หากมีการเรียกใช้เมธอดอื่น ขั้นตอนต่อไปคือการทราบตำแหน่งของบล็อกนี้
(lldb) memory read --size 8 --format x 0x16fd49f88
0x16fd49f88: 0x000000019f8fd218 0x00000000c2000000
0x16fd49f98: 0x000000010214777c 0x0000000102fb0e60
0x16fd49fa8: 0x000000015da32600 0x000000015ea1a430
0x16fd49fb8: 0x000000015cf5fee0 0x000000016fd49ff0
0x000000010214777c คือตำแหน่งของบล็อก แน่นอนว่า ASLR offset ปัจจุบันของ WeChat จะต้องถูกลบออก ที่อยู่สุดท้ายใน IDA คือ 0x10209377C ทันใดนั้นก็พบว่านี่คือรูทีนย่อยของ btnRelease
sub_10209377C รูทีนย่อยนี้เรียบง่ายมากและมีเพียงวิธีเดียวเท่านั้น selRef_logicCheckState_
ซึ่งอาจเป็นเป้าหมายของเรา มาดูกันก่อนว่าใครเป็นคนเรียกวิธีนี้
(lldb) br s -a 0xb4000+0x1020937BC
......
Process 3873 stopped
* thread #1: tid = 0xf62c4, 0x00000001021477bc WeChat`___lldb_unnamed_symbol108895$$WeChat + 64, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
frame #0: 0x00000001021477bc WeChat`___lldb_unnamed_symbol108895$$WeChat + 64
WeChat`___lldb_unnamed_symbol108895$$WeChat:
-> 0x1021477bc <+64>: adrp x8, 5489
0x1021477c0 <+68>: ldr x1, [x8, #1552]
0x1021477c4 <+72>: orr w2, wzr, #0x1
0x1021477c8 <+76>: ldp x29, x30, [sp, #16]
(lldb) po $x0
<MainFrameSightViewController: 0x15d1f0c00>
ฉันพบว่ายังคงถูกเรียกโดยวัตถุ MainFrameSightViewController ดังนั้น selRef_logicCheckState_
จะต้องอยู่ในไฟล์ส่วนหัวของคลาสนี้ด้วย
- (void)logicCheckState:(int)arg1;
มองหา [MainFrameSightViewController logicCheckState:] ในหน้าต่างด้านซ้ายของ IDA และพบว่าวิธีนี้ซับซ้อนมากและมีเหตุผลมากเกินไป ดังนั้นอย่ากังวลและดำเนินการอย่างช้าๆ เราพบว่าสวิตช์กระโดดที่ 0x102094D6C และแนวคิดนี้ชัดเจนมาก เราเพียงแต่ต้องค้นหาเส้นที่วิดีโอสั้นถูกถ่ายแล้วมองลงไป LLDB จะช่วยให้เราดูเส้นนั้นได้ ตั้งค่าเบรกพอยต์ที่ 0x102094D6C เบรกพอยต์นี้จะถูกทริกเกอร์หลายครั้งเมื่อถ่ายวิดีโอสั้น ๆ คุณสามารถปิดใช้งานเบรกพอยต์ก่อนถ่ายภาพ เปิดใช้งานเบรกพอยต์ก่อนปล่อย และพิมพ์ค่า x8 ในเวลานี้
(lldb) p/x $x8
(unsigned long) $38 = 0x0000000102174e10
x8 เป็นตัวชี้ และที่อยู่ที่ชี้ไปคือ 0x102174e10 ใช้ที่อยู่นี้ลบค่าชดเชย ASLR ปัจจุบันเพื่อค้นหาที่อยู่ฐานใน IDA พบว่าเป็น 0x102094E10 พบบรรทัดการประมวลผลแบบลอจิคัลสำหรับความสมบูรณ์ของการถ่ายภาพ ตลอดทาง หลังจากตำแหน่ง 0x102094E24 ให้ข้ามไปที่ 0x1020951C4
loc_1020951C4
ADRP X8, #selRef_hideTips@PAGE
LDR X1, [X8,#selRef_hideTips@PAGEOFF]
MOV X0, X19
BL _objc_msgSend
ADRP X8, #selRef_finishWriter@PAGE
LDR X1, [X8,#selRef_finishWriter@PAGEOFF]
MOV X0, X19
BL _objc_msgSend
ADRP X8, #selRef_turnCancelBtnForFinishRecording@PAGE
LDR X1, [X8,#selRef_turnCancelBtnForFinishRecording@PAGEOFF]
MOV X0, X19
BL _objc_msgSend
B loc_102095288
ในหมู่พวกเขา selRef_finishWriter
และ selRef_turnCancelBtnForFinishRecording
จำเป็นต้องมุ่งเน้นไปที่ทั้งสองวิธีนี้ ดูเหมือนจะหมายถึงจุดสิ้นสุดของการบันทึกวิดีโอสั้น ๆ มีแนวโน้มมากที่สุดในทั้งสองฟังก์ชันนี้ เมื่อดูที่ผู้โทร เราพบว่าทั้งสองวิธีนี้เป็นของ MainFrameSightViewController ดำเนินการตรวจสอบทั้งสองวิธีนี้ใน IDA ฉันพบวิธีการที่เรียกว่า f_switchToSendingPanel
ใกล้กับส่วนท้ายของ selRef_finishWriter
ที่ 0x102094248 ตั้งค่าเบรกพอยต์ จากนั้นจึงถ่ายวิดีโอ ฉันพบว่าวิธีนี้ไม่ได้ถูกทริกเกอร์ ไม่ควรเรียกอินเทอร์เฟซการเผยแพร่ผ่านเมธอดนี้ ดังนั้นให้กลับสู่เมธอด selRef_finishWriter
ต่อไป ให้เรียกเมธอด selRef_stopRecording
ที่ตำแหน่งของ 0x1020941DC และผู้เรียกที่พิมพ์ออกมาจะพบว่าเมธอดนี้เป็นของ SightFacade
และยังคงค้นหาต่อไป การใช้วิธีนี้ใน IDA selRef_stopRecord
ถูกเรียกอีกครั้งที่ตำแหน่ง 0x101F9BED4 ของเมธอดนี้ ผู้เรียกยังพบว่าเมธอดนี้เป็นของ SightCaptureLogicF4 เหมือนกับการปอกหัวหอมและยังคงมองหาการนำเมธอดนี้ไปใช้ selRef_finishWriting
ถูกเรียกอีกครั้งที่ตำแหน่ง 0x101A98778 ภายในวิธีนี้ เมื่อใช้หลักการเดียวกัน พบว่าวิธีนี้เป็นของ SightMovieWriter ลอกออกสามชั้นแล้ว มาทำต่อ:
เส้นสองเส้นจะถูกแบ่งที่ตำแหน่ง 0x10261D004 ใน SightMovieWriter - (void)finishWriting
เบรกพอยต์จะถูกตั้งค่าที่ตำแหน่งนี้ จากนั้นเบรกพอยต์จะถูกทริกเกอร์หลังจากถ่ายวิดีโอสั้น และค่าของ x19 จะถูกพิมพ์
(lldb) po $x19
<OS_dispatch_queue: CAPTURE.CALLBACK[0x13610bcd0] = { xrefcnt = 0x4, refcnt = 0x4, suspend_cnt = 0x0, locked = 1, target = com.apple.root.default-qos.overcommit[0x1a0aa3700], width = 0x0, running = 0x0, barrier = 1 }>
ดังนั้นโค้ดจะไม่ข้ามไปที่ loc_10261D054 แต่ไปทางซ้าย โดยในโค้ดทางด้านซ้ายจะพบว่ามีการเปิดใช้งานบล็อกนี้อยู่ ซึ่งก็คือ subroutine sub_10261D0AC และที่อยู่คือ 0x10261D0AC ให้ค้นหาที่อยู่นี้และโครงสร้างคือ ตามที่แสดงด้านล่าง:
จะเห็นได้ว่าส่วนใหญ่จะแบ่งเป็น 2 เส้น โดยเรากำหนดจุดพักไว้ที่ส่วนท้ายของช่องแรก ซึ่งก็คือ 0x10261D108 หลังจากจุดพักถูกทริกเกอร์หลังจากการถ่ายภาพเสร็จสิ้น ค่าของ x0 จะถูกพิมพ์เป็น 1 รหัสการประกอบนี่คือ
__text:000000010261D104 CMP X0, #2
__text:000000010261D108 B.EQ loc_10261D234
B.EQ จะข้ามไปที่ loc_10261D234 เฉพาะเมื่อผลลัพธ์ของขั้นตอนก่อนหน้าเป็น 0 แต่ผลลัพธ์ในที่นี้ไม่ใช่ 0 ให้เปลี่ยนค่าของ x0 เป็น 2 เพื่อให้ผลลัพธ์ของขั้นตอนก่อนหน้าเป็น 0
(lldb) po $x0
1
(lldb) register write $x0 2
(lldb) po $x0
2
ในเวลานี้ ปล่อยเบรกพอยต์และรอเพื่อข้ามไปยังอินเทอร์เฟซการเผยแพร่วิดีโอแบบสั้น ผลลัพธ์ก็คือค้างอยู่ในอินเทอร์เฟซนี้โดยไม่มีการตอบสนองใดๆ ดังนั้นฉันเดาว่าตรรกะในการใช้การข้ามควรอยู่ในบรรทัดทางด้านขวา และค้นหาต่อไปตามเส้นด้านขวา พบว่า วิธีการต่อไปนี้ถูกเรียกในตำแหน่งที่ถูกต้อง 0x10261D3AC
- (void)finishWritingWithCompletionHandler:(void (^)(void))handler;
วิธีนี้เป็นวิธีการใน AVAssetWriter ที่ระบบจัดเตรียมไว้ให้ ซึ่งเป็นการดำเนินการที่จะดำเนินการหลังจากการเขียนวิดีโอเสร็จสิ้น ในที่นี้จะมีการส่งบล็อกเข้ามา เนื่องจากมีพารามิเตอร์เพียงตัวเดียว ตัวแปรที่เกี่ยวข้องจึงเป็น x2 และค่า ของ x2 ถูกพิมพ์
(lldb) po $x2
<__NSStackBlock__: 0x16e086c78>
(lldb) memory read --size 8 --format x 0x16e086c78
0x16e086c78: 0x00000001a0aa5218 0x00000000c2000000
0x16e086c88: 0x00000001026d94b0 0x0000000102fc98c0
0x16e086c98: 0x0000000136229fd0 0x000000016e086d00
0x16e086ca8: 0x00000001997f5318 0xfffffffec9e882ff
และค้นหาตำแหน่งบล็อก 0x10261D4B0 ผ่านหน่วยความจำสแต็ก (ต้องลบออฟเซ็ต ASLR ออก)
sub_10261D4B0
var_20= -0x20
var_10= -0x10
STP X20, X19, [SP,#var_20]!
STP X29, X30, [SP,#0x20+var_10]
ADD X29, SP, #0x20+var_10
MOV X19, X0
LDR X0, [X19,#0x20]
ADRP X8, #selRef_stopAmr@PAGE
LDR X1, [X8,#selRef_stopAmr@PAGEOFF]
BL _objc_msgSend
LDR X0, [X19,#0x20]
ADRP X8, #selRef_compressAudio@PAGE
LDR X1, [X8,#selRef_compressAudio@PAGEOFF]
LDP X29, X30, [SP,#0x20+var_10]
LDP X20, X19, [SP+0x20+var_20],#0x20
B _objc_msgSend
; End of function sub_10261D4B0
มีเพียงสองวิธีเท่านั้นที่ถูกเรียก วิธีหนึ่งคือ selRef_stopAmr
เพื่อหยุด amr (รูปแบบเสียง) และอีกวิธีหนึ่งคือ selRef_compressAudio
เพื่อบีบอัดเสียง การดำเนินการถัดไปหลังจากการถ่ายภาพเสร็จสิ้น ไม่ควรวางไว้ในสองวิธีนี้ที่ฉันมองหามา เป็นเวลานานและฉันยังไม่มีเบาะแส ถนนสายนี้ดูเหมือนจะตายแล้ว อย่าไปยุ่ง ถอยอย่างมีกลยุทธ์และมองหาทางเข้าอื่น
ความสุขของการย้อนกลับคือการได้สัมผัสกับความสุขแห่งความสำเร็จบนเส้นทางการค้นหาความจริง คุณอาจไปผิดทาง และห่างไกลจากความจริงมากขึ้นเรื่อยๆ อย่าท้อแท้ จงปรับทิศทางและรักษาไว้ ก้าวไปข้างหน้า!
(เนื่องจาก WeChat ได้รับการอัปเกรดอย่างลับๆ ในเบื้องหลัง เนื้อหาต่อไปนี้จึงเป็น ASLR ของ WeChat เวอร์ชัน 6.3.30 และการวิเคราะห์ข้างต้นอิงตามเวอร์ชัน 6.3.28)
โปรดสังเกตว่าเมื่อคุณคลิกปุ่มกล้องที่มุมขวาบนของวงกลมของเพื่อน แผ่นงานจะปรากฏขึ้นที่ด้านล่าง อันแรกคือวิดีโอสั้น Sight เริ่มที่นี่ และใช้ Cycript เพื่อดูว่าเหตุการณ์ใดที่ปุ่ม Sight สอดคล้องกัน ถึง.
iPhone-5S:~ root# cycript -p "WeChat"
cy# [UIApp windows].toString()
`(
"<iConsoleWindow: 0x14d6ccc00; baseClass = UIWindow; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x14d7df110>; layer = <UIWindowLayer: 0x14d7d6f60>>",
"<SvrErrorTipWindow: 0x14eaa5800; baseClass = UIWindow; frame = (0 0; 320 45); hidden = YES; gestureRecognizers = <NSArray: 0x14e9e8950>; layer = <UIWindowLayer: 0x14e9e6510>>",
"<UITextEffectsWindow: 0x14ec38ba0; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = <UIWindowLayer: 0x14ec39360>>",
"<UITextEffectsWindow: 0x14e9c67a0; frame = (0 0; 320 568); layer = <UIWindowLayer: 0x14d683ff0>>",
"<UIRemoteKeyboardWindow: 0x14f226e40; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = <UIWindowLayer: 0x14d6f4de0>>",
"<NewYearActionSheet: 0x14f1704a0; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x14ef9bf90>; layer = <UIWindowLayer: 0x14ef61a20>>"
)`
cy# [#0x14f1704a0 recursiveDescription].toString()
แผ่นงานที่ด้านล่างคือ NewYearActionSheet จากนั้นพิมพ์แผนภาพโครงสร้าง UI ของ NewYearActionSheet (มันยาวเกินไป ฉันจะไม่โพสต์) จากนั้นพบว่า UIButton ที่สอดคล้องกับ Sight คือ 0x14f36d470
cy# [#0x14f36d470 allTargets]
[NSSet setWithArray:@[#"<NewYearActionSheet: 0x14f1704a0; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x14ef9bf90>; layer = <UIWindowLayer: 0x14ef61a20>>"]]]
cy# [#0x14f36d470 allControlEvents]
64
cy# [#0x14f36d470 actionsForTarget:#0x14f1704a0 forControlEvent:64]
@["OnDefaultButtonTapped:"]
เหตุการณ์ที่ผูกไว้กับปุ่มสามารถพบได้ผ่าน actionsForTarget:forControlEvent:
วิธีการของ UIControl วิธีการทริกเกอร์ของปุ่ม Sight คือ OnDefaultButtonTapped:
กลับไปที่ IDA และค้นหาวิธีนี้ใน NewYearActionSheet เราจะวิเคราะห์เฉพาะวิธีการ selRef_dismissWithClickedButtonIndex_animated
ต่อไป โดยการพิมพ์ตัวเรียก เราพบว่ายังคงเป็น NewYearActionSheet คลิกต่อไปเพื่อค้นหาเมธอด newYearActionSheet_clickedButtonAtIndex
ดูเหมือนว่าไม่ใช่ NewYearActionSheet เอง เราพบว่ามันเป็นของคลาส WCTimeLineViewController ทำตามจุดพักและเรียกเมธอด #selRef_showSightWindowForMomentWithMask_byViewController_scene
ที่ตำแหน่ง 0x1012B78CC เราพบว่าผู้เรียกเมธอดนี้มีค่าส่งคืน x0 ที่ตำแหน่ง 0x1012B78AC นี่คือคลาส SightFacade ฉันเดาว่าวิธีนี้อยู่ใน SightFacade I ไปที่ไฟล์ส่วนหัวเพื่อค้นหาวิธีนี้
- (void)showSightWindowForMomentWithMask:(id)arg1 byViewController:(id)arg2 scene:(int)arg3;
วิธีนี้ควรเป็นวิธีข้ามไปยังอินเทอร์เฟซวิดีโอขนาดเล็ก พิมพ์พารามิเตอร์แยกกันด้านล่าง
(lldb) po $x2
<UIImage: 0x14f046660>, {320, 568}
(lldb) po $x3
<WCTimeLineViewController: 0x14e214800>
(lldb) po $x4
2
(lldb) po $x0
<SightFacade: 0x14f124b40>
ในหมู่พวกเขา x2, x3 และ x4 สอดคล้องกับพารามิเตอร์สามตัวตามลำดับ x0 คือผู้เรียก ข้ามไปที่ด้านในของวิธีนี้เพื่อดูวิธีการนำไปใช้ พบว่าอินเทอร์เฟซการถ่ายวิดีโอสั้นได้รับการเตรียมใช้งานในวิธีนี้ ขั้นแรก MainFrameSightViewController จะเริ่มต้นขึ้น จากนั้น UINavigationController จะถูกสร้างขึ้นเพื่อใส่ MainFrameSightViewController เข้าไป จากนั้น MMWindowController ก็จะถูกเตรียมใช้งานเพื่อเรียก
- (id)initWithViewController:(id)arg1 windowLevel:(int)arg2;
วิธีการนี้จะใส่ UINavigationController เข้าไปและทำงานสร้าง UI ทั้งหมดสำหรับอินเทอร์เฟซการถ่ายวิดีโอสั้นให้เสร็จสิ้น หลังจากการถ่ายภาพเสร็จสิ้น ให้เข้าสู่อินเทอร์เฟซการเผยแพร่ ในเวลานี้ ให้ใช้ cycript เพื่อค้นหาว่าคอนโทรลเลอร์ปัจจุบันคือ SightMomentEditViewController จากนี้ ฉันเกิดแนวคิดขึ้นว่า จะข้ามอินเทอร์เฟซการถ่ายภาพก่อนหน้าโดยตรงไม่ได้หรือ เข้าสู่อินเทอร์เฟซการเผยแพร่? เราสร้าง SightMomentEditViewController ขึ้นมาเองและใส่ไว้ใน UINavigationController จากนั้นจึงใส่ตัวควบคุมการนำทางนี้ลงใน MMWindowController **(ฉันได้เขียนการปรับแต่งที่นี่เพื่อตรวจสอบ และแนวคิดการปรับแต่งเฉพาะจะถูกเขียนในภายหลัง)** ผลลัพธ์ก็คืออินเทอร์เฟซการเผยแพร่สามารถปรากฏขึ้นได้จริง แต่ NavgationBar ของแถบนำทางครอบคลุมต้นฉบับและอินเทอร์เฟซทั้งหมด โปร่งใส น่าเกลียด และหลังจากการเผยแพร่เสร็จสิ้น MWindowController ทั้งหมดจะไม่สามารถถูกทำลายได้ และจะยังคงอยู่ในอินเทอร์เฟซการเผยแพร่ นี่ไม่ใช่ผลลัพธ์ที่เราต้องการ แต่เราได้รับมากมาย อย่างน้อยเราก็สามารถเรียกอินเทอร์เฟซการเผยแพร่ได้โดยตรง และสามารถส่งต่อวิดีโอขนาดเล็กได้ตามปกติ โดยส่วนตัวแล้วฉันเดาว่าสาเหตุที่ไม่สามารถทำลายอินเทอร์เฟซปัจจุบันได้เนื่องจาก MWindowController สร้างหน้าต่างใหม่ซึ่งไม่เหมือนกับหน้าต่างหลักที่มี TimeLine ตั้งอยู่ วิธีการทริกเกอร์ปุ่มของ SightMomentEditViewController ไม่สามารถทำลายหน้าต่างนี้ได้ ดังนั้นฉันจึงมี ตัวหนา ฉันไม่สามารถแสดง SightMomentEditViewController โดยตรงบน WCTimeLineViewController ปัจจุบันได้หรือไม่
[WCTimelineVC presentViewController:editSightVC animated:YES completion:^{
}];
ไม่ดีเหรอที่จะแสดงแบบนี้? อย่างไรก็ตาม จากการสังเกตไฟล์ส่วนหัวของ SightMomentEditViewController รวมกับองค์ประกอบบนอินเทอร์เฟซเมื่อมีการเผยแพร่วิดีโอสั้น จึงคาดการณ์ว่าการสร้างตัวควบคุมนี้ต้องใช้แอตทริบิวต์อย่างน้อย 2 รายการ โดยรายการหนึ่งเป็นเส้นทางของวิดีโอสั้น และอีกรายการคือ ภาพขนาดย่อของวิดีโอสั้น ๆ สองคีย์นี้ หากกำหนดแอตทริบิวต์ให้กับ SightMomentEditViewController ก็ควรจะแสดงตามปกติ
SightMomentEditViewController *editSightVC = [[%c(SightMomentEditViewController) alloc] init];
NSString *localPath = [[self iOSREMediaItemFromSight] pathForSightData];
UIImage *image = [[self valueForKey:@"_sightView"] getImage];
[editSightVC setRealMoviePath:localPath];
[editSightVC setMoviePath:localPath];
[editSightVC setRealThumbImage:image];
[editSightVC setThumbImage:image];
[WCTimelineVC presentViewController:editSightVC animated:YES completion:^{
}];
อินเทอร์เฟซการเผยแพร่วิดีโอแบบสั้นสามารถแสดงได้ตามปกติและฟังก์ชันทั้งหมดสามารถใช้งานได้ตามปกติ ปัญหาเดียวคือปุ่มย้อนกลับไม่มีผลใด ๆ และ SightMomentEditViewController ไม่สามารถถูกทำลายได้ ใช้ cycript เพื่อตรวจสอบ actionEvent ของปุ่มซ้ายและพบว่าฟังก์ชันตอบสนองคือ - (void)popSelf;
จำเป็นต้องทำซ้ำวิธีนี้
- (void)popSelf
{
[self dismissViewControllerAnimated:YES completion:^{
}];
}
ในขณะนี้ ให้คลิกปุ่มย้อนกลับเพื่อออกตามปกติ นอกจากนี้ ยังพบวิธีการที่เรียกว่า - (void)sendSightToFriend;
ใน WCContentItemViewTemplateNewSight ซึ่งสามารถส่งต่อวิดีโอสั้น ๆ ให้เพื่อน ๆ ได้โดยตรง .
การส่งต่อวิดีโอสั้นรองรับ 4 ฟังก์ชัน ได้แก่ การส่งต่อไปยัง Moments การส่งต่อให้เพื่อน บันทึกไปยังอัลบั้มรูปภาพในเครื่อง และการคัดลอกลิงก์วิดีโอสั้นไปยังเพสต์บอร์ด หากไม่ได้ดาวน์โหลดวิดีโอสั้น การกดค้างจะแสดงเฉพาะลิงก์ URL ของวิดีโอสั้นเท่านั้น
ที่นี่เราจำเป็นต้องเชื่อมต่อสองคลาส ได้แก่ WCContentItemViewTemplateNewSight และ SightMomentEditViewController เชื่อมต่อเมธอด onLongTouch ใน WCContentItemViewTemplateNewSight จากนั้นเพิ่มเมนูป๊อปอัป และเพิ่มวิธีการตอบสนองตามลำดับ โค้ดเฉพาะมีดังนี้:
NSString *localPath = [[self iOSREMediaItemFromSight] pathForSightData];
UISaveVideoAtPathToSavedPhotosAlbum(localPath, nil, nil, nil);
}
NSString *localPath = [[self iOSREMediaItemFromSight] pathForSightData];
UISaveVideoAtPathToSavedPhotosAlbum(localPath, nil, nil, nil);
SightMomentEditViewController *editSightVC = [[%c(SightMomentEditViewController) alloc] init];
NSString *localPath = [[self iOSREMediaItemFromSight] pathForSightData];
UIImage *image = [[self valueForKey:@"_sightView"] getImage];
[editSightVC setRealMoviePath:localPath];
[editSightVC setMoviePath:localPath];
[editSightVC setRealThumbImage:image];
[editSightVC setThumbImage:image];
[WCTimelineVC presentViewController:editSightVC animated:YES completion:^{
}];
[self sendSightToFriend];
UIMenuController *menuController = [UIMenuController sharedMenuController];
if (menuController.isMenuVisible) return;//防止出现menu闪屏的情况
[self becomeFirstResponder];
NSString *localPath = [[self iOSREMediaItemFromSight] pathForSightData];
BOOL isExist =[[NSFileManager defaultManager] fileExistsAtPath:localPath];
UIMenuItem *retweetMenuItem = [[UIMenuItem alloc] initWithTitle:@"朋友圈" action:@selector(SLRetweetSight)];
UIMenuItem *saveToDiskMenuItem = [[UIMenuItem alloc] initWithTitle:@"保存到相册" action:@selector(SLSightSaveToDisk)];
UIMenuItem *sendToFriendsMenuItem = [[UIMenuItem alloc] initWithTitle:@"好友" action:@selector(SLSightSendToFriends)];
UIMenuItem *copyURLMenuItem = [[UIMenuItem alloc] initWithTitle:@"复制链接" action:@selector(SLSightCopyUrl)];
if(isExist){
[menuController setMenuItems:@[retweetMenuItem,sendToFriendsMenuItem,saveToDiskMenuItem,copyURLMenuItem]];
}else{
[menuController setMenuItems:@[copyURLMenuItem]];
}
[menuController setTargetRect:CGRectZero inView:self];
[menuController setMenuVisible:YES animated:YES];
ฉันใส่ไฟล์ปรับแต่งเฉพาะบน github WCSightRetwitter
@interface WCUrl : NSObject
@property(retain, nonatomic) NSString *url;
@end
@interface WCContentItem : NSObject
@property(retain, nonatomic) NSMutableArray *mediaList;
@end
@interface WCDataItem : NSObject
@property(retain, nonatomic) WCContentItem *contentObj;
@end
@interface WCMediaItem : NSObject
@property(retain, nonatomic) WCUrl *dataUrl;
- (id)pathForSightData;
@end
@interface MMServiceCenter : NSObject
+ (id)defaultCenter;
- (id)getService:(Class)arg1;
@end
@interface WCFacade : NSObject
- (id)getTimelineDataItemOfIndex:(long long)arg1;
@end
@interface WCSightView : UIView
- (id)getImage;
@end
@interface WCContentItemViewTemplateNewSight : UIView{
WCSightView *_sightView;
}
- (WCMediaItem *)iOSREMediaItemFromSight;
- (void)iOSREOnSaveToDisk;
- (void)iOSREOnCopyURL;
- (void)sendSightToFriend;
@end
@interface SightMomentEditViewController : UIViewController
@property(retain, nonatomic) NSString *moviePath;
@property(retain, nonatomic) NSString *realMoviePath;
@property(retain, nonatomic) UIImage *thumbImage;
@property(retain, nonatomic) UIImage *realThumbImage;
- (void)makeInputController;
@end
@interface MMWindowController : NSObject
- (id)initWithViewController:(id)arg1 windowLevel:(int)arg2;
- (void)showWindowAnimated:(_Bool)arg1;
@end
@interface WCTimeLineViewController : UIViewController
- (long long)calcDataItemIndex:(long long)arg1;
@end
@interface MMTableViewCell : UIView
@end
@interface MMTableView : UIView
- (id)indexPathForCell:(id)cell;
@end
THEOS_DEVICE_IP = 192.168.0.115//手机所在的IP
include $(THEOS)/makefiles/common.mk
ARCHS = arm64//支持的CPU架构
TWEAK_NAME = WCTimelineSightRetweet
WCTimelineSightRetweet_FILES = Tweak.xm
WCTimelineSightRetweet_FRAMEWORKS = UIKit CoreGraphics//导入系统的framework
include $(THEOS_MAKE_PATH)/tweak.mk
after-install::
install.exec "killall -9 WeChat"//安装完成杀掉的进程
ไม่จำเป็นต้องแก้ไขไฟล์ควบคุม จากนั้นดำเนินการคำสั่ง make package install
เพื่อติดตั้งบนโทรศัพท์มือถือ WeChat จะถูกฆ่า จากนั้นเปิด WeChat อีกครั้ง เพิ่มฟังก์ชันการส่งต่อวิดีโอสั้น ๆ
ติดตั้ง macports (ขั้นตอนการติดตั้งต้องใช้การเชื่อมต่อ VPN มิฉะนั้นการติดตั้งจะไม่สำเร็จ)
หลังจากติดตั้ง MacPorts ให้เปิดเทอร์มินัลแล้วป้อน sudo port -v selfupdate
เพื่ออัปเดต MacPort เป็นเวอร์ชันล่าสุด ซึ่งอาจใช้เวลานาน
หลังจากอัปเดต MacPorts ให้ติดตั้งไฟล์ DPKG และป้อน sudo port -f install dpkg
ในเทอร์มินัล
ดาวน์โหลดและติดตั้ง iOSOpendev หากการติดตั้งล้มเหลว คุณสามารถใช้ Command + L
เพื่อตรวจสอบปัญหาระหว่างการติดตั้ง
PackageKit: Install Failed: Error Domain=PKInstallErrorDomain Code=112 "运行软件包“iOSOpenDev-1.6-2.pkg”的脚本时出错。" UserInfo={NSFilePath=./postinstall, NSURL=file://localhost/Users/ice/Downloads/iOSOpenDev-1.6-2.pkg#iodsetup.pkg, PKInstallPackageIdentifier=com.iosopendev.iosopendev162.iod-setup.pkg, NSLocalizedDescription=运行软件包“iOSOpenDev-1.6-2.pkg”的脚本时出错。} {
NSFilePath = "./postinstall";
NSLocalizedDescription = "U8fd0U884cU8f6fU4ef6U5305U201ciOSOpenDev-1.6-2.pkgU201dU7684U811aU672cU65f6U51faU9519U3002";
NSURL = "file://localhost/Users/ice/Downloads/iOSOpenDev-1.6-2.pkg#iodsetup.pkg";
PKInstallPackageIdentifier = "com.iosopendev.iosopendev162.iod-setup.pkg";
}
วิธีแก้ปัญหา: ดาวน์โหลดโฟลเดอร์ข้อมูลจำเพาะใน iOSOpenDevInstallSolve
5. เพื่อแก้ไขปัญหาความล้มเหลวในการติดตั้ง ให้เปิดโฟลเดอร์ข้อมูลจำเพาะที่ดาวน์โหลดมาในขั้นตอนที่ 4 ควรมีไฟล์ 8 ไฟล์ในนั้น หากคุณติดตั้ง xcode หลายไฟล์ โปรดใส่ไฟล์เหล่านั้นลงใน xcodes ที่เกี่ยวข้อง
(1) ไฟล์สี่ไฟล์ที่ขึ้นต้นด้วย iPhoneOS จะถูกวางไว้ในโฟลเดอร์ /Application/Xcode/Content/Developer/Platforms/IphoneOS.platform/Developer/Library/Xcode/Specifications (หากไม่ใช่ โปรดสร้างโฟลเดอร์ข้อมูลจำเพาะด้วยตัวเอง)
(2) ไฟล์อีกสี่ไฟล์ที่ขึ้นต้นด้วย iPhone Simulator จะถูกวางไว้ในโฟลเดอร์ /Application/Xcode/Content/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Specifications (หากไม่ใช่ โปรดสร้างขึ้นมาด้วย)
(3) สร้างโฟลเดอร์ usr ภายใต้โฟลเดอร์ /Application/Xcode/Content/Developer/Platforms/iPhoneSimulator.platform/Developer/ และสร้างโฟลเดอร์ชื่อ bin ใต้โฟลเดอร์ usr
หมายเหตุ: บางครั้งจะมีข้อความแจ้งว่าการติดตั้งล้มเหลว เปิดโปรเจ็กต์ใหม่ใน Xcode หากมี iOSOpenDev ในเมนูตัวเลือกของโปรเจ็กต์ แสดงว่าการติดตั้งสำเร็จ
หากต้องการติดตั้งแพ็คเกจ ipa คุณยังสามารถใช้เครื่องมือ เช่น itool ได้ แต่โปรแกรมติดตั้ง idevice สามารถดูขั้นตอนการติดตั้ง ซึ่งทำให้เราค้นหาสาเหตุของข้อผิดพลาดได้ง่ายขึ้น
ดำเนินการคำสั่ง
brew install ideviceinstaller
หากคุณได้รับแจ้งว่าไม่พบคำสั่งชง แสดงว่ายังไม่ได้ติดตั้ง Homebrew บน Mac ของคุณ
ข้อความแสดงข้อผิดพลาดทั่วไป:
ERROR: Could not connect to lockdownd, error code -5
ในขณะนี้ เพียงติดตั้ง libimobiledevice ใหม่ (เนื่องจาก ideviceinstaller อาศัยปลั๊กอินอื่นๆ อีกมากมาย)
ดำเนินการคำสั่งต่อไปนี้:
$ brew uninstall libimobiledevice
$ brew install --HEAD libimobiledevice
ดาวน์โหลดเครื่องมือลงนาม iOS App Signer ใหม่* (บันทึกการดำเนินการบรรทัดคำสั่งได้มากมาย ลงนามใหม่ได้ในคลิกเดียว!)*
(3) ดาวน์โหลดแอปพลิเคชัน WeChat ที่ถูกแฮ็ก
เนื่องจากแพ็คเกจ AppStore ถูกเข้ารหัส (เชลล์) และไม่สามารถลงนามซ้ำได้ คุณจึงต้องใช้แพ็คเกจที่เชลล์แล้ว คุณสามารถใช้ dumpdecrypted เพื่อดัมพ์เชลล์ด้วยตัวเอง หรือคุณสามารถใช้ PP Assistant หรือ itool Assistant โดยตรงเพื่อดาวน์โหลดเวอร์ชันเจลเบรค ของแอปพลิเคชั่น WeChat ที่ถูกแฮ็ก
(4) ติดตั้ง yololib
yololib สามารถแทรก dylib ลงในไฟล์ไบนารี WeChat เพื่อให้ Hook ของคุณมีประสิทธิภาพ หลังจากดาวน์โหลด ให้คอมไพล์และรับ yololib
#####(1) สร้างไลบรารี่แบบคงที่ iOSOpendev ได้รับการติดตั้งในขั้นตอนก่อนหน้า ตอนนี้เปิดโครงการใหม่ใน Xcode โปรเจ็กต์ iOSOpendev จะปรากฏในอินเทอร์เฟซการเลือกโปรเจ็กต์ ที่นี่ เราจำเป็นต้องเลือกโปรเจ็กต์ CaptainHook มีไฟล์ .mm ที่สร้างขึ้นใหม่เพียงไฟล์เดียว เราจำเป็นต้องเขียนวิธี hook ทั้งหมดในไฟล์นี้เท่านั้น
เนื่องจากเครื่องที่ไม่ใช่เจลเบรคไม่สามารถติดตั้งปลั๊กอินปรับแต่งเพื่อเชื่อมต่อแอปพลิเคชันดั้งเดิม เช่น เครื่องเจลเบรคได้ CaptainHook จึงใช้กลไกรันไทม์เพื่อใช้งานฟังก์ชันต่างๆ เช่น การกำหนดคลาสและการแทนที่เมธอดโดยใช้คำสั่งมาโคร ต่อไปนี้เป็นคำแนะนำสั้นๆ เกี่ยวกับวิธีการใช้งาน:
CHDeclareClass(WCContentItemViewTemplateNewSight);
CHDeclareClass(ClassName)
บ่งชี้ว่าคลาสใดที่จะเชื่อมต่อ และโดยปกติจะเขียนไว้ที่จุดเริ่มต้นของการดำเนินการในคลาสนี้
CHDeclareMethod0(id, WCContentItemViewTemplateNewSight, SLSightDataItem){......}
CHDeclareMethod(count, return_type, class_type, name1, arg1, ....)
หมายถึงการสร้างเมธอดใหม่ count หมายถึงจำนวนพารามิเตอร์ของเมธอดนี้ return_type หมายถึงประเภทการส่งคืน class_type เติมชื่อคลาสของเมธอดนี้ name1 หมายถึงชื่อเมธอด arg1 แทนพารามิเตอร์แรก หากไม่มีพารามิเตอร์ ให้ปล่อยว่างไว้ และอื่นๆ
CHOptimizedMethod0(self, void, WCContentItemViewTemplateNewSight, onLongTouch){
CHSuper(0, className, Method);//可选
......
}
CHOptimizedMethod(count, optimization, return_type, class_type, name1, type1, arg1)
หมายถึงการเชื่อมต่อกับเมธอดดั้งเดิม (ถ้า CHSuper(0, className, Method)
หมายถึงการคัดลอกวิธีดั้งเดิม CHSuper หมายถึงการเรียกวิธีดั้งเดิมที่ตำแหน่งปัจจุบัน) count หมายถึงจำนวนพารามิเตอร์วิธี hook การเพิ่มประสิทธิภาพโดยทั่วไปจะเติมในตัวเอง return_type เป็นประเภทค่าส่งคืนของวิธี class_type เติมในชื่อคลาสของ คลาสปัจจุบัน name1 คือชื่อเมธอด arg1 คือพารามิเตอร์ หากไม่มีพารามิเตอร์ ให้กรอก arg และอื่นๆ
CHConstructor
{
@autoreleasepool
{
CHLoadLateClass(WCContentItemViewTemplateNewSight);
CHHook(0, WCContentItemViewTemplateNewSight, onLongTouch);
}
}
นี่คือฟังก์ชันการเข้าของ CaptainHook คลาสที่เชื่อมต่อทั้งหมดจะต้องถูกประกาศให้โหลดที่นี่ และจะต้องประกาศวิธีการในคลาสที่เชื่อมต่อไว้ที่นี่
จากนั้นคุณสามารถเขียนโค้ดลงในคลาสและเมธอดได้ โค้ดยาวเกินไป ดังนั้นฉันจึงไม่โพสต์มันลงใน GitHub ด้วย MMPlugin
โครงการนี้รวมถึงฟังก์ชั่นของการส่งต่อวิดีโอสั้น ๆ คว้าซองจดหมายสีแดงโดยอัตโนมัติและการปรับเปลี่ยนขั้นตอนการออกกำลังกาย WeChat
หมายเหตุ: หากคุณใช้คลาสระบบอย่าลืมนำเข้าไลบรารีคลาสที่เกี่ยวข้อง (เช่น UIKIT) และไฟล์ส่วนหัวมิฉะนั้นจะมีการรายงานข้อผิดพลาดระหว่างการรวบรวม
หลังจากการรวบรวมสำเร็จคุณสามารถค้นหาไลบรารีสแตติกที่รวบรวมได้ในโฟลเดอร์ผลิตภัณฑ์
ค้นหาใน Finder และคัดลอกเพื่อใช้ในภายหลัง
วัสดุที่คุณควรมี ณ จุดนี้รวมถึง:
ค้นหาไฟล์ไบนารี WeChat จากแอพ WeChat ดั้งเดิมและคัด ลอก เพื่อใช้ในภายหลัง
ดำเนินการคำสั่งต่อไปนี้เพื่อฉีด mmplugin.dylib ลงในไฟล์ไบนารี wechat
LeonLei-MBP:WeChat gaoshilei$ ./yololib WeChat MMPlugin.dylib
เมื่อดำเนินการคำสั่งนี้ตรวจสอบให้แน่ใจว่า Yololib, WeChat และ WeChat.app อยู่ในไดเรกทอรีเดียวกัน
หลังจากเสร็จสิ้นให้คัดลอก mmplugin.dylib และ weChat ไปยัง wechat.app ดั้งเดิมเขียนทับไฟล์ weChat ดั้งเดิม
เปิดผู้ลงนามแอป iOS และเลือกพารามิเตอร์ต่างๆดังที่แสดงด้านล่าง:
สิ่งที่ฉันเลือกที่นี่คือใบรับรองระดับองค์กร
เชื่อมต่อกับโทรศัพท์มือถือของคุณและดำเนินการคำสั่งต่อไปนี้เพื่อตรวจสอบว่า iDeviceInstaller เชื่อมต่อกับโทรศัพท์มือถือหรือไม่:
LeonLei-MBP:WeChat gaoshilei$ ideviceinfo
หากมีการพิมพ์ข้อมูลโทรศัพท์มือถือจำนวนมากหมายความว่าการเชื่อมต่อนั้นประสบความสำเร็จและคุณสามารถติดตั้งแพ็คเกจ IPA ได้ ดำเนินการคำสั่งต่อไปนี้เพื่อติดตั้ง:
LeonLei-MBP:WeChat gaoshilei$ ideviceinstaller -i WeChat.ipa
WARNING: could not locate iTunesMetadata.plist in archive !
WARNING: could not locate Payload/WeChat.app/SC_Info/WeChat.sinf in archive !
Copying ' WeChat.ipa ' to device... DONE.
Installing ' com.xxxxxxxxxxxx '
- CreatingStagingDirectory (5%)
- ExtractingPackage (15%)
- InspectingPackage (20%)
- TakingInstallLock (20%)
- PreflightingApplication (30%)
- InstallingEmbeddedProfile (30%)
- VerifyingApplication (40%)
- CreatingContainer (50%)
- InstallingApplication (60%)
- PostflightingApplication (70%)
- SandboxingApplication (80%)
- GeneratingApplicationMap (90%)
- Complete
หลังจากการติดตั้งเสร็จสมบูรณ์ให้เปิด WeChat บนโทรศัพท์ของคุณเพื่อลองใช้คุณสมบัติใหม่ที่เราเพิ่ม! หากลิงค์บางอย่างติดอยู่จะมีการรายงานข้อผิดพลาด โปรดดูการเรนเดอร์: