Pembaruan 2020.1.14 tidak memerlukan instalasi jailbreak
Artikel ini adalah tutorial membalikkan file biner WeChat untuk mewujudkan penerusan video pendek di Momen. Dari kode perakitan awal hingga instalasi penandatanganan ulang akhir dan operasi lainnya, artikel ini akan mengajari Anda langkah demi langkah cara bermain dengan WeChat! Setelah Anda mempelajarinya, akan mudah untuk merekayasa balik fungsi WeChat lainnya.
Artikel ini dibagi menjadi dua bagian karena panjangnya. Bagian pertama menjelaskan pekerjaan sebaliknya, yaitu bagaimana menemukan fungsi dan metode yang relevan untuk diterapkan. Bagian kedua menjelaskan cara menginstal ulang tanda tangan pada mesin yang tidak di-jailbreak dan tweak instalasi pada mesin yang sudah di-jailbreak.
Bagian kedua dari teks juga memberikan kode untuk WeChat untuk secara otomatis mengambil amplop merah dan mengubah jumlah langkah WeChat. Ini dapat ditemukan langkah demi langkah dengan mengikuti rutinitas artikel ini dan tidak akan diulangi di sini.
Sebelum berlatih, Anda perlu menyiapkan ponsel yang sudah di-jailbreak dan menginstal semua alat yang tercantum di bawah ini. IDA dan Reveal keduanya adalah versi crack. Versi asli IDA berharga lebih dari 2.000 dolar. Ini sangat berharga untuk alat rekayasa balik yang luar biasa. Namun, jika Anda bukan perusahaan yang berspesialisasi dalam rekayasa balik, tidak ada perlu menggunakan versi asli. Versi Windows crack berikutnya akan baik-baik saja, saya belum dapat menemukannya di Mac. Anda dapat menggunakan hopper untuk menggantikan IDA di Mac, yang juga merupakan alat rekayasa balik yang sangat kuat. Tanpa basa-basi lagi, mari kita mulai!
Catatan: File biner WeChat yang dibalik dalam artikel ini adalah versi 6.3.28. Jika ini adalah versi WeChat yang berbeda, alamat dasar dalam file biner juga berbeda.
Lingkungan terbalik untuk mesin yang di-jailbreak MacOS + iPhone5S 9.1 <br> Pertama gunakan dumpdecrypted untuk menghancurkan shell WeChat (jika Anda tidak tahu caranya, silakan baca tutorial yang saya tulis ini), dapatkan file WeChat.decrypted, dan pertama-tama masukkan file ini ke IDA untuk dianalisis (file biner sekitar 60MB membutuhkan waktu sekitar 40 menit untuk dianalisis oleh IDA End), gunakan class-dump untuk mengekspor semua file header
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
Saya punya ibu mertua! Ada total 8.000 file header, dan WeChat benar-benar memiliki banyak pekerjaan! Tenangkan emosi Anda, kumpulkan pikiran Anda dan lanjutkan. Untuk mendapatkan link download video pendek, temukan Tampilan yang memutar video tersebut, dan ikuti petunjuk untuk menemukan URL video pendek tersebut. Gunakan Reveal untuk melihat jendela pemutaran video pendek. Anda dapat melihat bahwa objek WCContentItemViewTemplateNewSigh adalah jendela pemutaran video pendek. SubViewnya mencakup WCSightView, SightView, dan SightPlayerView. Saat menyimpan video ke favorit, tekan lama video tersebut untuk memunculkan opsi, jadi mungkin ada metode terkait isyarat di kelas WCContentItemViewTemplateNewSight. Temukan petunjuk di file header yang baru saja diekspor.
- (void)onLongTouch;
- (void)onLongPressedWCSight:(id)arg1;
- (void)onLongPressedWCSightFullScreenWindow:(id)arg1;
Metode ini terkait dengan isyarat tekan lama. Temukan fungsi ini di IDA dan lihat satu per satu. onLongPressedWCSight dan onLongPressedWCSightFullScreenWindow relatif sederhana, onLongTouch relatif panjang, dan saya menemukan bahwa metode Favorites_Add dipanggil secara internal, karena ketika Anda menekan lama video, opsi yang keluar adalah Favorit, dan saya melihat pemanggilan fungsi ini
ADRP X8, #selRef_sightVideoPath@PAGE
LDR X1, [X8,#selRef_sightVideoPath@PAGEOFF]
Saya mendapat alamat video pendeknya di sini. Dapat berspekulasi bahwa fungsi ini terkait dengan koleksi.
(lldb) im li -o -f
[ 0] 0x000000000003c000 /var/mobile/Containers/Bundle/Application/2F1D52EC-C57E-4F95-B715-EF04351232E8/WeChat.app/WeChat(0x000000010003c000)
Anda dapat melihat bahwa ASLR WeChat adalah 0x3c000. Temukan alamat dasar ketiga fungsi ini di IDA dan atur breakpoint masing-masing.
(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
Kembali ke WeChat dan tekan lama video pendek untuk melihat bagaimana breakpoint dipicu.
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
……
Ditemukan bahwa breakpoint 2 terpicu terlebih dahulu, kemudian breakpoint 1 terpicu, dan kemudian breakpoint 2 dan 1 terpicu masing-masing setelah Breakpoint 3 sangat sepi. Anda dapat mengecualikan hubungan antara onLongPressedWCSightFullScreenWindow dan koleksi video pendek. Jejak video pendek harus ditemukan di dua metode lainnya. Temukan C sampai V, dan temukan M dengan mengikuti petunjuk yang telah dicoba dan diuji! Gunakan cycript untuk memasukkan WeChat dan dapatkan Pengontrol tempat tampilan yang memutar video pendek berada.
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>"
Temukan Pengontrol yang menjadi milik WCContentItemViewTemplateNewSight melalui rantai responden dan itu adalah WCTimeLineViewController. Tidak ada petunjuk berharga yang ditemukan dalam file header kelas ini, tetapi kami memperhatikan bahwa tampilan tempat video pendek berada adalah milik MMTableVIewCell (lihat bagan analisis Reveal di atas), yang merupakan TableView dan data sel yang paling dikenal untuk setiap iOS. Itu ditetapkan melalui metode proxy UITableViewDataSource - tableView:cellForRowAtIndexPath:
Melalui metode ini, Anda pasti dapat mengetahui bayangan M. Temukan [WCTimeLineViewController tableView:cellForRowAtIndexPath:]
di IDA dan temukan alamat dasar 0x10128B6B0:
__text:000000010128B6B0 ADRP X8, #selRef_genNormalCell_indexPath_@PAGE
Fungsi di sini adalah metode untuk menghasilkan sel di WCTimeLineViewController Selain metode ini, ada tiga metode lain untuk menghasilkan sel di kelas ini:
- (void)genABTestTipCell:(id)arg1 indexPath:(id)arg2;
- (void)genRedHeartCell:(id)arg1 indexPath:(id)arg2;
- (void)genUploadFailCell:(id)arg1 indexPath:(id)arg2;
Dari arti harfiahnya, kita dapat menebak bahwa normal seharusnya merupakan metode untuk menghasilkan sel video kecil. Terus mencari petunjuk di IDA
__text:0000000101287CC8 ADRP X8, #selRef_getTimelineDataItemOfIndex_@PAGE
Cara di atas terdapat pada metode genNormalCell:IndexPath:
:. Anda dapat dengan aman menebak bahwa metode ini adalah metode untuk mendapatkan data TimeLine (momen). Data video pendek juga harus diperoleh melalui metode ini, dan IDA dapat melihatnya panggil metode ini yang disebut selRef_getTimelineDataItemOfIndex_
, memperoleh DataItem tampaknya merupakan sumber data sel! Selanjutnya, gunakan LLDB untuk menyetel breakpoint guna memverifikasi dugaan. Anda dapat menemukan alamat dasar yang sesuai dengan metode ini melalui IDA: 0x101287CE4. Pertama cetak offset ASLR dari menjalankan 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)
Jadi lokasi breakpoint kita adalah 0x50000+0x101287CE4
(lldb) br s -a 0x50000+0x101287CE4
Breakpoint 1: where = WeChat`___lldb_unnamed_symbol63721$$WeChat + 252, address = 0x00000001012d7ce4
Cetak nilai x0
(lldb) po $x0
Class name: WCDataItem, addr: 0x15f5f03b0
tid: 12393001887435993280
username: wxid_z8twcz4o18fg12
createtime: 1477360950
commentUsers: (
)
contentObj: <WCContentItem: 0x15f57d000>
Dapatkan objek WCDataItem. Nilai x0 di sini adalah nilai kembalian setelah eksekusi selRef_getTimelineDataItemOfIndex_
, lalu ubah nilai x0.
(lldb) register write $x0 0
(lldb) c
Saat ini, Anda akan menemukan bahwa konten video kecil yang ingin kami segarkan semuanya kosong.
Sampai disini kita sudah menemukan cara untuk mendapatkan sumber data dari video pendek tersebut. Pertanyaannya adalah bagaimana cara mendapatkan WCDataItem ini? Lanjutkan melihat status pemanggilan fungsi analisis IDA:
WCTimeLineViewController - (batal)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
......
Parameter yang diteruskan ke selRef_getTimelineDataItemOfIndex_
adalah x2. Anda dapat melihat bahwa x21 yang diteruskan ke x2 adalah nilai kembalian dari fungsi selRef_calcDataItemIndex_
, yang merupakan tipe data panjang yang tidak ditandatangani. Melanjutkan analisis, pemanggil fungsi selRef_getTimelineDataItemOfIndex_
adalah nilai kembalian selRef_getService_
pada langkah sebelumnya. Setelah analisis breakpoint, ditemukan bahwa itu adalah objek WCFacade
. Mari kita selesaikan panggilan ke selRef_getTimelineDataItemOfIndex_
:
Pemanggilnya adalah nilai kembalian selRef_getService_
; parameternya adalah nilai kembalian selRef_calcDataItemIndex_
<br> Mari kita alihkan perhatian kita ke kedua fungsi tersebut dan menggunakan prinsip yang sama untuk menganalisis bagaimana keduanya mengimplementasikan panggilan tersebut.
selRef_getService_
terlebih dahulu:MMServiceCenter
. Melihat ke atas, x19 ditetapkan pada posisi 0x101287C88 adalah kembalinya nilai [MMServiceCenter defaultCenter]
[WCFacade class]
.selRef_calcDataItemIndex_
:WCTimeLineViewController
peneleponnya x0 di posisi 0x101287C58.selRef_section
0x101287C4C ditemukan selRef_section
yang masuk berasal dari selRef_section
atau x3WCTimeLineViewController - (void)genNormalCell:(id) indexPath:(id)
, jadi parameter selRef_calcDataItemIndex_
adalah [IndexPath section]
.getTimelineDataItemOfIndex:
bisa lewat [[MMServiceCenter defaultCenter] getService:[WCFacade class]]
untuk mendapatkannya, parameternya dapat diperoleh melalui fungsi berikut
[WCTimeLineViewController calcDataItemIndex:[indexPath section]]
Selalu merasa ada sesuatu yang hilang? Kami belum mendapatkan indexPath! Langkah selanjutnya adalah mendapatkan indexPath yang relatif sederhana, karena kita berada di [WCContentItemViewTemplateNewSight onLongTouch]
, sehingga kita bisa mendapatkan MMTableViewCell, MMTableView dan WCTimeLineViewController secara berurutan melalui [self nextResponder]
, lalu mendapatkan indexPath melalui [MMTableView indexPathForCell:MMTableViewCell]
.
Setelah melakukan ini, kita telah mendapatkan objek WCDataItem. Fokus selanjutnya harus pada WCDataItem, dan akhirnya mendapatkan video pendek yang kita inginkan. Carilah petunjuk di file header kelas ini. Karena video hanya dapat diputar setelah diunduh, maka jalur video tersebut harus diperoleh di sini, jadi perhatikan atribut atau metode yang terkait dengan url dan jalurnya, lalu temukan yang berikut ini. tersangka.
@property(retain, nonatomic) NSString *sourceUrl2;
@property(retain, nonatomic) NSString *sourceUrl;
- (id)descriptionForKeyPaths;
- (id)keyPaths;
Kembali ke LLDB dan cetak nilai-nilai ini dengan breakpoint untuk melihat apa yang ada di sana.
(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
Tidak ada petunjuk berharga, tapi saya perhatikan ada WCContentItem di WCDataItem. Tampaknya satu-satunya cara untuk memulai adalah di sini.
@property(retain, nonatomic) NSString *linkUrl;
@property(retain, nonatomic) NSString *linkUrl2;
@property(retain, nonatomic) NSMutableArray *mediaList;
Cetak di 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>
)
Ada objek WCMediaItem dalam array mediaList. Media umumnya digunakan untuk mewakili video dan audio. Temukan file header dengan cepat dan cari.
@property(retain, nonatomic) WCUrl *dataUrl;
- (id)pathForData;
- (id)pathForSightData;
- (id)pathForTempAttachVideoData;
- (id)videoStreamForData;
Di antara atribut dan metode di atas, pathForSightData
adalah yang paling mungkin mendapatkan jalur video pendek.
(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
Dapatkan url jaringan dan jalur lokal dari video pendek! Di sini Anda dapat menggunakan iFunBox atau scp untuk menyalin file ini dari kotak pasir untuk melihat apakah itu video pendek yang harus diputar oleh sel ini.
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
Buka dengan QuickTime dan temukan bahwa itu memang video pendek yang kita cari. Verifikasi lagi apakah URL-nya benar. Buka dataUrl yang tercetak di atas di browser dan temukan juga video pendek ini. Menganalisis kelas ini kita dapat menarik kesimpulan sebagai berikut:
Pada titik ini, analisis jalur dan metode akuisisi video pendek telah selesai. Untuk mencapai penerusan, kami perlu terus menganalisis rilis WeChat Moments.
Bagian ini adalah jalan memutar yang saya ambil ketika mencari fungsi penerusan video pendek. Pada akhirnya, saya tidak menemukan cara untuk mengimplementasikannya. Namun, bagian ini juga memberikan beberapa ide dan metode yang umum digunakan dalam rekayasa balik. Jika Anda tidak ingin membacanya, Anda dapat melompat ke bagian kedua.
Buka antarmuka perekaman video pendek dan gunakan cycript untuk menyuntikkannya. Kita perlu mencari tahu metode mana yang digunakan untuk mempublikasikan video pendek, dan kemudian memeriksa jendela mana yang ada di jendela saat ini (karena perekaman video pendek tidak ada). dilakukan di jendela kunci Aplikasi UIA)
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>>"
)
Ditemukan bahwa halaman saat ini memiliki total 5 jendela, di antaranya MMUIWindow adalah jendela tempat pengambilan video pendek. Cetak struktur pohon UI-nya.
cy# [#0x127796440 recursiveDescription]
Hasil cetakannya lumayan panjang, jadi tidak akan saya posting. Temukan tombol ini yang merupakan tombol untuk merekam video pendek
| | | | | | <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>>
dan kemudian jalankan
cy# [#0x1277a9d70 setHidden:YES]
Saya menemukan bahwa tombol tembak menghilang, yang membenarkan kecurigaan saya. Untuk menemukan peristiwa respons tombol, Anda dapat menemukannya melalui target
cy# [#0x1277a9d70 allTargets]
[NSSet setWithArray:@[#"<MainFrameSightViewController: 0x1269a4600>"]]]
cy# [#0x1277a9d70 allControlEvents]
193
cy# [#0x1277a9d70 actionsForTarget:#0x1269a4600 forControlEvent:193]
null
Saya menemukan bahwa tombol tersebut tidak memiliki tindakan yang sesuai, dan ini aneh! UIButton harus memiliki target dan tindakan, jika tidak, Tombol tidak dapat merespons peristiwa. Mari kita coba ControlEvents lainnya
cy# [#0x1277a9d70 actionsForTarget:#0x1269a4600 forControlEvent:UIControlEventTouchDown]
@["btnPress"]
cy# [#0x1277a9d70 actionsForTarget:#0x1269a4600 forControlEvent:UIControlEventTouchUpOutside]
@["btnRelease"]
cy# [#0x1277a9d70 actionsForTarget:#0x1269a4600 forControlEvent:UIControlEventTouchUpInside]
@["btnRelease"]
Ternyata ketiga ControlEvents ini memiliki tindakan yang sesuai. Mari kita lihat nilai dari ketiga enumerasi ini.
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;
Terlihat bahwa UIControlEventTouchDown bernilai 1, UIControlEventTouchUpInside bernilai 128, UIControlEventTouchUpOutside bernilai 64, dan jumlah ketiganya tepat 193! Ternyata saat memanggil [#0x1277a9d70 allControlEvents]
, nilai yang dikembalikan seharusnya berupa enumerasi. Jika ada beberapa enumerasi, tambahkan nilainya. Saya merasakan hal yang sama! Baru saja kami mencetak tindakan yang terkait dengan tiga ControlEvents dan dilanjutkan dengan LLDB+IDA untuk analisis dinamis.
Karena kami perlu menemukan cara untuk mempublikasikan video pendek, kami tidak peduli dengan fungsi btnPress
yang sesuai. Kami fokus pada btnRelease
, sebuah metode yang akan dipanggil setelah tombol pengambilan gambar dilepaskan. Temukan metode ini di IDA dan atur breakpoint berikutnya setelah menemukannya
(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
Rekam video pendek dengan ponsel Anda lalu lepaskan, memicu breakpoint, yang menunjukkan bahwa tebakan kami benar. Melanjutkan analisis, kami menemukan bahwa kode tersebut berasal dari sisi kanan gambar di atas. Setelah melihatnya, tidak ada cara untuk melompat ke rilis video. Namun, jika Anda perhatikan dengan cermat, ada blok, yaitu blok penundaan sistem dan terletak di 0x102093760. Kemudian kita ikuti breakpoint dan lompat ke alamat yang disimpan di x16 di 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>
Ditemukan bahwa parameter x2 yang diteruskan adalah sebuah blok. Mari kita tinjau kembali fungsi pengiriman_after.
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
Fungsi ini memiliki tiga parameter yaitu pengiriman_time_t, pengiriman_queue_t, dan pengiriman_block_t. X2 yang dicetak di sini adalah blok yang akan diteruskan, jadi kami memperkirakan akan ada penundaan setelah merekam video pendek, dan kemudian mengeksekusi blok yang baru saja dilewati. jadi x2 harus Jika ada pemanggilan metode lain, langkah selanjutnya adalah mengetahui lokasi blok ini.
(lldb) memory read --size 8 --format x 0x16fd49f88
0x16fd49f88: 0x000000019f8fd218 0x00000000c2000000
0x16fd49f98: 0x000000010214777c 0x0000000102fb0e60
0x16fd49fa8: 0x000000015da32600 0x000000015ea1a430
0x16fd49fb8: 0x000000015cf5fee0 0x000000016fd49ff0
0x000000010214777c adalah lokasi blok. Tentu saja, offset ASLR WeChat saat ini harus dikurangi. Alamat akhir di IDA adalah btnRelease
. Subrutin ini sangat sederhana dan hanya memiliki satu metode selRef_logicCheckState_
yang mungkin menjadi target kita. Mari kita lihat dulu siapa yang menyebut metode ini
(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>
Saya menemukan bahwa itu masih dipanggil oleh objek MainFrameSightViewController, jadi selRef_logicCheckState_
juga harus ada di file header kelas ini. Saya mencari dan menemukannya.
- (void)logicCheckState:(int)arg1;
Cari [MainFrameSightViewController logicCheckState:] di jendela kiri IDA dan temukan bahwa metode ini sangat rumit dan memiliki terlalu banyak logika, jadi jangan khawatir dan lakukan secara perlahan. Kami menemukan lompatan tombol di 0x102094D6C, dan idenya sangat jelas. Kami hanya perlu menemukan garis di mana video pendek itu diambil dan melihat ke bawah. Tetapkan breakpoint pada 0x102094D6C. Breakpoint ini akan dipicu beberapa kali saat merekam video pendek. Anda dapat menonaktifkan breakpoint sebelum merekam, mengaktifkan breakpoint sebelum melepaskannya, dan mencetak nilai x8 saat ini.
(lldb) p/x $x8
(unsigned long) $38 = 0x0000000102174e10
x8 adalah sebuah penunjuk, dan alamat yang dituju adalah 0x102174e10. Gunakan alamat ini dikurangi offset ASLR saat ini untuk menemukan alamat dasar di IDA sepenuhnya. Setelah posisi 0x102094E24, lompat ke 0x1020951C4. Cabang ini memiliki konten yang lebih sedikit dan berisi tiga fungsi.
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
Diantaranya, selRef_finishWriter
dan selRef_turnCancelBtnForFinishRecording
perlu difokuskan. Kedua metode ini sepertinya berarti akhir dari perekaman video pendek. Petunjuknya kemungkinan besar ada pada kedua fungsi ini. Dengan melihat pemanggilnya, kami menemukan bahwa kedua metode ini milik MainFrameSightViewController. Lanjutkan untuk memeriksa kedua metode ini di IDA. Saya menemukan metode bernama f_switchToSendingPanel
di dekat akhir selRef_finishWriter
pada 0x102094248, menetapkan breakpoint, lalu merekam video, saya menemukan bahwa metode ini tidak terpicu. Antarmuka penerbitan tidak boleh dipanggil melalui metode ini, jadi lanjutkan kembali ke metode selRef_finishWriter
; panggil metode selRef_stopRecording
di lokasi 0x1020941DC, dan pemanggil yang mencetaknya menemukan bahwa metode ini milik SightFacade
, dan terus mencari penerapan metode ini di IDA. selRef_stopRecord
dipanggil lagi pada posisi 0x101F9BED4 dari metode ini. Penelepon juga menemukan bahwa metode ini milik SightCaptureLogicF4. selRef_finishWriting
dipanggil lagi pada posisi 0x101A98778 di dalam metode ini. Dengan menggunakan prinsip yang sama, ditemukan bahwa metode ini milik SightMovieWriter. Tiga lapisan sudah terkelupas, mari kita lanjutkan:
Dua baris dibagi pada posisi 0x10261D004 di SightMovieWriter - (void)finishWriting
Breakpoint diatur pada posisi ini, dan kemudian breakpoint dipicu setelah merekam video pendek, dan nilai x19 dicetak.
(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 }>
Oleh karena itu, kode tidak akan melompat ke loc_10261D054 tetapi ke kiri. Pada kode di sebelah kiri, ditemukan bahwa blok ini diaktifkan. Blok ini adalah subrutin sub_10261D0AC dan alamatnya adalah 0x10261D0AC seperti yang ditunjukkan di bawah ini:
Terlihat bahwa ini terutama dibagi menjadi dua baris. Kami menetapkan breakpoint di akhir kotak pertama, yaitu 0x10261D108. Setelah breakpoint dipicu setelah pemotretan, nilai x0 dicetak sebagai 1. Kode perakitan di sini adalah
__text:000000010261D104 CMP X0, #2
__text:000000010261D108 B.EQ loc_10261D234
B.EQ akan melompat ke loc_10261D234 hanya jika hasil langkah sebelumnya adalah 0, namun hasil di sini bukan 0. Ubah nilai x0 menjadi 2 sehingga hasil langkah sebelumnya adalah 0.
(lldb) po $x0
1
(lldb) register write $x0 2
(lldb) po $x0
2
Pada saat ini, lepaskan breakpoint dan tunggu untuk melompat ke antarmuka penerbitan video pendek. Hasilnya adalah terjebak di antarmuka ini tanpa respons apa pun, jadi saya kira logika untuk mewujudkan lompatan tersebut harus berada di garis di sebelah kanan. dan terus mencari di sepanjang garis di sebelah kanan: Ditemukan bahwa metode berikut dipanggil di 0x10261D3AC di sebelah kanan
- (void)finishWritingWithCompletionHandler:(void (^)(void))handler;
Metode ini adalah metode di AVAssetWriter yang disediakan oleh sistem. Ini adalah operasi yang dilakukan setelah penulisan video selesai. Di sini, sebuah blok diteruskan. Karena hanya ada satu parameter, variabel yang bersangkutan adalah x2, dan nilainya dari x2 dicetak.
(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
Dan temukan posisi blok 0x10261D4B0 melalui memori tumpukan (offset ASLR perlu dikurangi)
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
Hanya dua metode yang dipanggil, satu adalah selRef_stopAmr
untuk menghentikan amr (format audio), dan yang lainnya adalah selRef_compressAudio
untuk mengompresi audio. Operasi selanjutnya setelah pengambilan gambar tidak boleh ditempatkan dalam dua metode ini dan saya masih belum tahu. Jalan ini sepertinya mati, jangan sampai mendapat masalah, mundurlah secara strategis dan cari pintu masuk lainnya.
Asyiknya berjalan sebaliknya adalah Anda bisa merasakan nikmatnya kesuksesan dalam perjalanan menemukan kebenaran. Anda mungkin juga menuju ke arah yang salah dan semakin jauh dari kebenaran dan teruslah bergerak maju!
(Karena WeChat diam-diam ditingkatkan di latar belakang, konten berikut adalah ASLR WeChat versi 6.3.30, dan analisis di atas didasarkan pada versi 6.3.28)
Perhatikan bahwa ketika Anda mengklik tombol kamera di sudut kanan atas lingkaran teman, sebuah Lembar akan muncul di bagian bawah. Yang pertama adalah video pendek Sight. Mulai di sini dan gunakan cycript untuk melihat acara mana yang sesuai dengan tombol Sight ke.
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()
Lembar di bawah adalah NewYearActionSheet, lalu cetak diagram struktur pohon UI NewYearActionSheet (terlalu panjang jadi saya tidak akan mempostingnya). Kemudian temukan bahwa UIButton yang sesuai dengan Sight adalah 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:"]
Peristiwa yang terikat pada tombol dapat ditemukan melalui actionsForTarget:forControlEvent:
dari UIControl. Metode pemicu tombol Sight adalah OnDefaultButtonTapped:
selRef_dismissWithClickedButtonIndex_animated
ke IDA dan temukan metode ini di NewYearActionSheet. , dengan mencetak pemanggilnya, kami menemukan bahwa itu masih NewYearActionSheet. Lanjutkan mengklik untuk menemukan metode newYearActionSheet_clickedButtonAtIndex
. Tampaknya itu bukan NewYearActionSheet itu sendiri. Ikuti breakpoint dan panggil metode #selRef_showSightWindowForMomentWithMask_byViewController_scene
pada posisi 0x1012B78CC. Melalui pengamatan, kami menemukan bahwa pemanggil metode ini adalah nilai kembalian x0 pada posisi 0x1012B78AC pergi ke file header untuk menemukannya
- (void)showSightWindowForMomentWithMask:(id)arg1 byViewController:(id)arg2 scene:(int)arg3;
Metode ini seharusnya menjadi metode untuk melompat ke antarmuka video kecil. Cetak parameternya secara terpisah di bawah
(lldb) po $x2
<UIImage: 0x14f046660>, {320, 568}
(lldb) po $x3
<WCTimeLineViewController: 0x14e214800>
(lldb) po $x4
2
(lldb) po $x0
<SightFacade: 0x14f124b40>
Diantaranya, x2, x3, dan x4 masing-masing berhubungan dengan tiga parameter. x0 adalah pemanggilnya. Ditemukan bahwa antarmuka perekaman video pendek diinisialisasi dalam metode ini Pertama, MainFrameSightViewController diinisialisasi, kemudian UINavigationController dibuat untuk memasukkan MainFrameSightViewController ke dalamnya, dan kemudian MMWindowController diinisialisasi untuk memanggil
- (id)initWithViewController:(id)arg1 windowLevel:(int)arg2;
Metode ini memasukkan UINavigationController dan menyelesaikan semua pekerjaan pembuatan UI untuk antarmuka perekaman video pendek. Setelah pengambilan gambar selesai, masuk ke antarmuka penerbitan. Saat ini, gunakan cycript untuk menemukan bahwa Pengontrol saat ini adalah SightMomentEditViewController. Dari sini, muncul ide. Bukankah cukup dengan melewati antarmuka pengambilan gambar sebelumnya dan langsung masuk ke antarmuka penerbitan ? Kami membuat sendiri SightMomentEditViewController dan meletakkannya di UINavigationController, lalu meletakkan pengontrol navigasi ini di MMWindowController. **(Saya telah menulis perubahan di sini untuk verifikasi, dan ide perubahan spesifik akan ditulis kemudian)** Hasilnya adalah antarmuka penerbitan memang dapat muncul, tetapi NavgationBar pada bilah navigasi mencakup yang asli, dan keseluruhan antarmukanya transparan, jelek, dan setelah penerbitan selesai, seluruh MMWindowController tidak dapat dimusnahkan, dan masih tetap berada di antarmuka penerbitan. Ini bukan hasil yang kami inginkan, tapi kami mendapatkan banyak keuntungan. Setidaknya kami bisa langsung menghubungi antarmuka penerbitan, dan video kecil bisa diteruskan secara normal. Dugaan pribadi saya adalah alasan mengapa antarmuka saat ini tidak dapat dimusnahkan adalah karena MMWindowController membuat jendela baru, yang tidak sama dengan keyWindow tempat TimeLine berada. Metode pemicu tombol SightMomentEditViewController tidak dapat menghancurkan jendela ini, jadi saya punya tebakan yang berani. Tidak bisakah saya menampilkan SightMomentEditViewController langsung di WCTimeLineViewController saat ini?
[WCTimelineVC presentViewController:editSightVC animated:YES completion:^{
}];
Bukankah menyenangkan menampilkannya seperti ini? Namun, dengan mengamati file header SightMomentEditViewController, dikombinasikan dengan elemen pada antarmuka saat video pendek dirilis, diperkirakan bahwa pembuatan pengontrol ini memerlukan setidaknya dua atribut, satu adalah jalur video pendek, dan yang lainnya adalah thumbnail dari video pendek. Kedua kunci ini Jika atribut diberikan kepada SightMomentEditViewController, maka akan ditampilkan secara normal.
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:^{
}];
Antarmuka penerbitan video pendek dapat ditampilkan secara normal dan semua fungsi dapat digunakan secara normal. Satu-satunya masalah adalah tombol kembali tidak berpengaruh dan SightMomentEditViewController tidak dapat dimusnahkan. Gunakan cycript untuk memeriksa actionEvent dari tombol kiri dan temukan bahwa fungsi responsnya adalah - (void)popSelf;
Mengklik tombol kiri untuk kembali memicu metode pop, tetapi pengontrol ini tidak ada di navgationController, jadi tidak valid perlu mengulangi metode ini
- (void)popSelf
{
[self dismissViewControllerAnimated:YES completion:^{
}];
}
Saat ini, klik tombol kembali untuk keluar secara normal. Selain itu, metode yang disebut - (void)sendSightToFriend;
ditemukan di WCContentItemViewTemplateNewSight, yang dapat langsung meneruskan video pendek ke teman .
Penerusan video pendek mendukung 4 fungsi, meneruskan ke Momen, meneruskan ke teman, menyimpan ke album foto lokal, dan menyalin tautan video pendek ke karton. Jika video pendek tidak terdownload, menekan lama hanya akan menampilkan link url video pendek tersebut.
Di sini kita perlu menghubungkan dua kelas, yaitu WCContentItemViewTemplateNewSight dan SightMomentEditViewController. Kaitkan metode onLongTouch di WCContentItemViewTemplateNewSight lalu tambahkan menu pop-up, dan tambahkan metode respons secara bergantian.
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];
Saya meletakkan file tweak khusus di github WCSightRetweet
@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"//安装完成杀掉的进程
File kontrol tidak perlu dimodifikasi, lalu jalankan perintah make package install
untuk menginstalnya di ponsel. WeChat akan dimatikan, lalu buka kembali WeChat. Fungsi penerusan video pendek telah ditambahkan.
Instal macports (proses instalasi memerlukan koneksi VPN, jika tidak maka instalasi tidak akan berhasil)
Setelah menginstal MacPorts, buka terminal dan masukkan sudo port -v selfupdate
untuk memperbarui MacPorts ke versi terbaru, yang mungkin memerlukan waktu lama.
Setelah memperbarui MacPorts, instal file DPKG dan masukkan sudo port -f install dpkg
di terminal.
Unduh dan instal iOSOpendev. Jika instalasi gagal, Anda dapat menggunakan Command + L
untuk memeriksa masalah selama instalasi.
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";
}
Ini solusinya: Download folder Spesifikasi di iOSOpenDevInstallSolve
5. Untuk memperbaiki masalah kegagalan instalasi, buka folder Spesifikasi yang diunduh pada langkah 4. Seharusnya ada 8 file di dalamnya. Jika Anda memiliki beberapa xcode yang diinstal, masukkan ke dalam xcode yang sesuai.
(1) Keempat file yang dimulai dengan iPhoneOS ditempatkan di folder /Application/Xcode/Content/Developer/Platforms/IphoneOS.platform/Developer/Library/Xcode/Specifications (jika belum, silakan buat sendiri folder Spesifikasinya)
(2) Empat file lainnya yang dimulai dengan iPhone Simulator ditempatkan di folder /Application/Xcode/Content/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Specifications (jika tidak, harap buat juga)
(3) Buat folder usr di bawah folder /Application/Xcode/Content/Developer/Platforms/iPhoneSimulator.platform/Developer/, dan buat folder bernama bin di bawah folder usr.
Catatan: Terkadang akan ada prompt bahwa instalasi gagal. Buka proyek baru di Xcode. Jika ada iOSOpenDev di menu opsi proyek, itu berarti instalasi berhasil.
Untuk menginstall paket ipa juga bisa menggunakan tools seperti itool, namun ideviceinstaller dapat melihat proses instalasinya sehingga memudahkan kita mencari penyebab errornya.
jalankan perintah
brew install ideviceinstaller
Jika Anda ditanya bahwa perintah brew tidak dapat ditemukan, berarti Homebrew belum diinstal di Mac Anda.
Pesan kesalahan umum:
ERROR: Could not connect to lockdownd, error code -5
Saat ini, cukup instal ulang libimobiledevice (karena ideviceinstaller bergantung pada banyak plug-in lain)
Jalankan perintah berikut:
$ brew uninstall libimobiledevice
$ brew install --HEAD libimobiledevice
Unduh alat penandatanganan ulang Penandatangan Aplikasi iOS* (simpan banyak operasi baris perintah, tanda tangan ulang dengan satu klik!)*
(3) Unduh aplikasi WeChat yang diretas
Karena paket AppStore dienkripsi (di-shell) dan tidak dapat ditandatangani ulang, Anda harus menggunakan yang di-shell. Anda dapat menggunakan dumpdecrypted untuk membuang shell sendiri, atau Anda dapat langsung menggunakan asisten PP atau asisten itool untuk mengunduh versi yang sudah di-jailbreak. dari aplikasi WeChat yang telah di-shell.
(4) Instal yololib
yololib dapat memasukkan dylib ke dalam file biner WeChat, sehingga Hook Anda dapat efektif. Setelah mengunduh, kompilasi dan dapatkan yololib
#####(1) Hasilkan perpustakaan statis. iOSOpendev telah diinstal pada langkah sebelumnya. Sekarang buka proyek baru di Xcode. Proyek iOSOpendev akan muncul di antarmuka pemilihan proyek. Hanya ada satu proyek yang baru dibuat. File .mm, kita hanya perlu menulis semua metode hook di file ini.
Karena mesin yang tidak di-jailbreak tidak dapat menginstal plug-in tweak untuk menghubungkan aplikasi asli seperti mesin yang sudah di-jailbreak, CaptainHook menggunakan mekanisme Runtime untuk mengimplementasikan fungsi seperti definisi kelas dan penggantian metode menggunakan perintah makro.
CHDeclareClass(WCContentItemViewTemplateNewSight);
CHDeclareClass(ClassName)
menunjukkan kelas mana yang akan dihubungkan, dan biasanya ditulis di awal operasi pada kelas ini.
CHDeclareMethod0(id, WCContentItemViewTemplateNewSight, SLSightDataItem){......}
CHDeclareMethod(count, return_type, class_type, name1, arg1, ....)
artinya membuat metode baru, count berarti jumlah parameter metode ini, return_type berarti tipe kembalian, class_type mengisi nama kelas metode ini, nama1 artinya nama metode, arg1 mewakili parameter pertama, jika tidak ada parameter biarkan kosong, dan seterusnya.
CHOptimizedMethod0(self, void, WCContentItemViewTemplateNewSight, onLongTouch){
CHSuper(0, className, Method);//可选
......
}
CHOptimizedMethod(count, optimization, return_type, class_type, name1, type1, arg1)
berarti mengaitkan metode asli (jika CHSuper(0, className, Method)
berarti menyalin metode asli, CHSuper berarti memanggil metode asli pada posisi saat ini), count berarti jumlah parameter metode kait, optimasi umumnya mengisi diri, return_type adalah metode mengembalikan tipe nilai, class_type mengisi nama kelas dari kelas saat ini, nama1 adalah nama metode, arg1 adalah parameternya, jika tidak ada parameter, isikan arg, dan seterusnya.
CHConstructor
{
@autoreleasepool
{
CHLoadLateClass(WCContentItemViewTemplateNewSight);
CHHook(0, WCContentItemViewTemplateNewSight, onLongTouch);
}
}
Ini adalah fungsi entri CaptainHook. Semua kelas yang terhubung harus dideklarasikan di sini untuk dimuat, dan metode dalam kelas tersebut harus dinyatakan terhubung di sini.
Kemudian Anda dapat menulis kode ke dalam kelas dan metode. Kode tersebut terlalu panjang jadi saya tidak akan mempostingnya di github dengan MMPlugin.
Proyek ini mencakup fungsi meneruskan video pendek, mengambil amplop merah secara otomatis, dan memodifikasi langkah-langkah latihan WeChat secara otomatis dan mengubah langkah-langkah latihan WeChat dapat dimatikan secara manual.
Catatan: Jika Anda menggunakan kelas sistem, ingatlah untuk mengimpor pustaka kelas yang sesuai (seperti UIKIT) dan file header, jika tidak kesalahan akan dilaporkan selama kompilasi.
Setelah kompilasi yang berhasil, Anda dapat menemukan pustaka statis yang dikompilasi di folder produk.
Temukan di Finder dan salin untuk digunakan nanti.
Bahan yang harus Anda miliki pada saat ini termasuk:
Temukan file biner WeChat dari aplikasi WeChat asli dan salin untuk digunakan nanti.
Jalankan perintah berikut untuk menyuntikkan mmplugin.dylib ke dalam file biner weChat.
LeonLei-MBP:WeChat gaoshilei$ ./yololib WeChat MMPlugin.dylib
Saat menjalankan perintah ini, pastikan bahwa Yololib, WeChat, dan WeChat.App berada di direktori yang sama.
Setelah selesai, salin mmplugin.dylib dan weChat ke wechat.app asli, menimpa file weChat asli.
Buka iOS App Signer dan pilih berbagai parameter seperti yang ditunjukkan di bawah ini:
Apa yang saya pilih di sini adalah sertifikat tingkat perusahaan.
Hubungkan ke ponsel Anda dan jalankan perintah berikut untuk memeriksa apakah IdeviceInstaller terhubung ke ponsel:
LeonLei-MBP:WeChat gaoshilei$ ideviceinfo
Jika banyak informasi ponsel dicetak, itu berarti koneksi berhasil dan Anda dapat menginstal paket IPA. Jalankan perintah berikut untuk menginstal:
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
Setelah instalasi selesai, buka WeChat di ponsel Anda untuk mencoba fitur baru yang kami tambahkan! Jika tautan tertentu macet, kesalahan akan dilaporkan. Silakan lihat renderingnya: