- iOS ऐप reverse engineering के लिए आम तौर पर चल रहे ऐप को observe और manipulate कर पाना ज़रूरी होता है, लेकिन इस widget ऐप में debugger block, code injection block, और jailbreak detection तीनों साथ इस्तेमाल किए गए थे
- मुख्य block
ptraceके PT_DENY_ATTACH या उसी प्रभाव वाले direct system call (svc #0x80) से लागू किया जा सकता है, इसलिए केवलptracebreakpoint से इसे पकड़ा नहीं जा सकता - direct system call को bypass करने के लिए binary में
mov w16, #26pattern ढूँढकरsvcकी जगह पर breakpoint लगाया गया औरlldb jumpसे उस instruction को skip किया गया - jailbreak detection के बाद फ़ोन को soft-reboot/respring कराने वाला व्यवहार
snapshotViewAfterScreenUpdates:को infinite loop में कॉल करने वाले function से जुड़ा था, और function की शुरुआत मेंthread returnदेकर इसे skip किया गया - code injection के बाद होने वाला crash किसी अलग runtime framework check से ज़्यादा App Group permission loss के कारण था, और
containerURLForSecurityApplicationGroupIdentifier:को temporary directory पर बदलने वाली swizzle से इसे सामान्य device पर भी चलाया जा सका
कई सुरक्षा परतों वाला iOS widget ऐप
- लक्ष्य App Store का एक widget ऐप था, जिसमें सामान्य widget ऐप्स की तुलना में ज़्यादा मज़बूत defensive behavior शामिल था
- debugger attach block
- code injection होने पर ऐप बंद करना
- jailbreak स्थिति में चलाने पर पूरे फ़ोन का soft-reboot/respring होना
- iOS ऐप्स में jailbreak detection या code obfuscation जैसी सुरक्षा तकनीकें जोड़ना असामान्य नहीं है, लेकिन इस ऐप में कई तरीक़े एक साथ इस्तेमाल किए गए थे
- ऐप के अंदर के दूसरे दिलचस्प व्यवहारों को आगे की पोस्ट के लिए छोड़ा गया है
PT_DENY_ATTACH से debugger attach block
- jailbroken device पर आम तौर पर
sshसे कनेक्ट करकेdebugserverचलाया जाता है, और दूसरे कंप्यूटर केlldbसे जुड़कर ऐप को debug किया जा सकता है - इसी तरीके से इस ऐप पर
debugserverattach करने की कोशिश करने पर Segmentation fault हुआ और attach विफल हो गया - इसकी वजह
ptraceकेPT_DENY_ATTACHrequest से जुड़ी थीptraceiOS में private API है और macOS में public APIPT_DENY_ATTACHआगे आने वाले parent process trace को reject करने वाला flag सेट करता है- अगर पहले से trace हो रहा हो तो ऐप
ENOTSUPस्थिति के साथ terminate हो जाता है - इस flag वाले process को parent trace करने की कोशिश करे तो parent side पर segmentation violation होता है
- साधारण implementation
ptrace(PT_DENY_ATTACH, 0, 0, 0)कॉल से की जा सकती है- iOS private API होने के कारण असली कॉल में
dlopen,dlsymसेlibsystem_kernel.dylibकाptracesymbol ढूँढना पड़ता है - इस तरीके को
ptraceपर breakpoint लगाकर औरthread returnसे कॉल skip करके काफ़ी आसानी से bypass किया जा सकता है
- iOS private API होने के कारण असली कॉल में
आसान bypass काम क्यों नहीं आया
PT_DENY_ATTACHकेवल कॉल होने के बाद debugger को रोकता है, इसलिए ऐप कोड चलने से पहले attach कर लिया जाए तो bypass point बनाया जा सकता हैdebugserverको process पर सीधे attach करने के बजाय पहले चलाकर,lldbमेंprocess attach --name TopWidget --waitforसे ऐप launch का इंतज़ार करने पर ऐप कोड चलने से पहले attach किया जा सकता है- लेकिन इस ऐप में
b ptracebreakpoint शुरू में resolve ही नहीं हुआ, और बाद में resolve होने पर भी hit हुए बिना ऐप बंद हो गया - वजह यह थी कि ऐप
ptracefunction call के बजाय उसी असर वाले direct system call का इस्तेमाल कर रहा था
direct system call की जगह ढूँढना
ptracefunction की disassembly में मुख्य system callsvc #0x80शामिल होता हैx0मेंPT_DENY_ATTACHका मान31होता हैx1,x2,x3में इस्तेमाल न होने वाले argument0होते हैंx16मेंptracesystem call number26होता है
- ऐप
ptracefunction को कॉल किए बिना inline assembly से वही register values सेट करके सीधेsvc #0x80चला सकता है- यह तरीका
dlopen,dlsymजैसी संदिग्ध private API lookup से बचाता है - और
ptraceजैसे common function पर breakpoint लगाकर पकड़ना मुश्किल बना देता है
- यह तरीका
- bypass करने के लिए decrypted app binary को disassembler में खोलकर
ptracesystem call की location खोजनी पड़ी - खोज का target
mov x16, #26या उसी register के 32-bit viewmov w16, #26था- armconverter.com से
mov x16, #26के bytes50 03 80 D2लेकर binary search में इस्तेमाल किया जा सकता है mov x16, #26पर कोई result नहीं मिला, जबकिmov w16, #26search में 4 result मिले
- armconverter.com से
- उनमें से दो result के आस-पास की instructions अपेक्षित pattern से मेल नहीं खाती थीं, और तीसरे result में नीचे जैसा code मिला
MOV X0, #0x1FMOV X1, #0MOV X2, #0MOV X3, #0MOV W16, #0x1ASVC 0x80
- चौथा result उसी function की दूसरी branch था, और इसी function को debugger attach block की जगह के रूप में पहचाना गया
svc instruction skip करना
- disassembler में मिले
svcaddresses0x102A2BB14और0x102A2BB68थे lldbमें binary-relative address को actual load address में बदलने के लिए-s TopWidgetके साथ breakpoint सेट किया गयाbr s -a 0x102A2BB14 -s TopWidgetbr s -a 0x102A2BB68 -s TopWidget
- execution जारी रखने पर
svc #0x80की जगह breakpoint hit हुआ - सबसे आसान bypass यह था कि अगले instruction address पर jump करके system call को execute ही न होने दिया जाए
- उदाहरण में current instruction के अगले address
0x10327bb18परjump *0x10327bb18चलाया गया
- उदाहरण में current instruction के अगले address
- इस प्रक्रिया के बाद debugger attached स्थिति में ऐप के अंदर प्रवेश किया जा सका
फ़ोन को soft-reboot कराने वाला behavior
- debugger attach bypass करने के बाद भी ऐप ने फ़ोन को soft-reboot/respring कराने वाला सुरक्षा behavior चलाया
- इस बार
lldbअभी भी attach था, इसलिए process कोSIGKILLमिलने की स्थिति और stacktrace देखा जा सका - stacktrace में screen content capture का flow दिखाई दिया
QuartzCoreकाCARenderServerSnapshotUIKitCoreका_UISnapshotScreenWindowsRectAfterCommit- ऐप के अंदर
TopWidgetका unnamed symbol
lldb image lookupसे runtime address को binary-relative address0x100041898में बदलकर disassembler में उस function को देखा गया- decompile result में function infinite loop के अंदर सिर्फ़ ये काम दोहराता था
+[UIScreen mainScreen]कॉल- लौटे हुए screen object पर
snapshotViewAfterScreenUpdates:कॉल - result को इस्तेमाल किए बिना release करना
snapshotViewAfterScreenUpdates:view snapshot बनाने वाला public API है, लेकिन यह ऐप memory-intensive call को infinite loop में दोहरा रहा था- जुड़े हुए वीडियो में दिखा कि इस call की उत्पत्ति
com.apple.tw.twrrnotification से जुड़ी है, और फ़ोन risk check pass न करे तो respring होता है - bypass के लिए उस function की शुरुआत में breakpoint लगाकर hit होने पर
thread returnसे function execution skip किया गया
code injection पर होने वाला crash
- debugging के दौरान screen के button accessibility info logging जैसी जटिल utility को ऐप में inject किए गए framework में implement करके debugger से कॉल किया जा सकता है
- jailbroken device न होने पर भी Frida या Flex inject करके ऐप का शुरुआती exploration किया जा सकता है
- आम तौर पर ऐसी injection ऐप को resign करने वाले tool से की जाती है, और उदाहरण के तौर पर Sideloadly इस्तेमाल हुआ
- यह ऐप resign के बाद चलाते ही तुरंत crash हो गया
- crash stack के शीर्ष address
0x1002027D4को disassembler में देखने परBRKinstruction मिला, जो nil force-unwrap जैसी intentional crash स्थिति से मेल खाता है - decompiled code में संदिग्ध call
containerURLForSecurityApplicationGroupIdentifier:थी- यह method उसी group के apps और extensions के साथ साझा किए जा सकने वाले folder URL को लौटाती है
- App Group code signing प्रक्रिया में परिभाषित होता है
- code injection के बाद resign करने से मूल app signature हट गया और App Group permission भी खो गई
- इसलिए URL की जगह
nilलौटा होगा, और ऐप ने उसे force-unwrap किया होगा जिससे crash हुआ
- widget ऐप को home screen widget दिखाने वाली extension के साथ App Group साझा करना होता है, इसलिए यह समस्या रक्षा-उद्देश्य वाला behavior कम और सामान्य code-signing समस्या ज़्यादा लगती है
App Group समस्या bypass करना
- सबसे आसान समाधान ऐप को resign न करना है
- jailbroken device पर jailbreak tweak से framework inject करते समय ऐप को resign किए बिना काम किया जा सकता है
- invalid signature वाला code चलाना, या मनचाहे app को मनचाहे group में जोड़ना भी संभव है
- अगर jailbroken device न हो और resign ज़रूरी हो, तब भी छोटे framework से method swizzle करके bypass किया जा सकता है
- उदाहरण code
NSFileManagerकेcontainerURLForSecurityApplicationGroupIdentifier:को replace करता है- मूल method कॉल होने पर replacement method चलती है
- replacement method shared container की जगह
temporaryDirectoryलौटाती है
- यह replacement ऐप के मूल इच्छित behavior जैसा नहीं है
- मूल ऐप को app और extension, दोनों के लिए accessible shared folder चाहिए
- temporary directory ऐसा shared folder नहीं है
- लेकिन अगर उद्देश्य सिर्फ़ main app behavior देखना हो तो यह काफ़ी हो सकता है
- ऐसा छोटा patch app extension को तोड़ सकता है
- अगर केवल main app की basic functionality चाहिए तो यह समस्या नहीं भी हो सकती
- बड़ा bypass यह है कि नया App Group बनाया जाए, main app और सभी extensions को उसी group के साथ resign किया जाए, और संबंधित methods को swizzle करके नया group identifier इस्तेमाल कराया जाए
- यह काफ़ी बड़ा काम है, और अगर बहुत ज़रूरी न हो तो jailbroken device का इंतज़ाम करना बेहतर हो सकता है
- इस framework को
Flexजैसे tool के साथ inject करने पर सामान्य device पर भी ऐप सही से चलने लगा - jailbroken device पर पहले वाले anti-debugging और respring protection को फिर से bypass करना पड़ता है, लेकिन उसके बाद
Flexinjected स्थिति में ऐप के अंदर जाया जा सकता है
अंतिम स्थिति
- आख़िर में ऐप ऐसी स्थिति में पहुँचा जहाँ debugger attach, jailbreak detection bypass, और code injection तीनों संभव हो गए
- वास्तव में ऐप के अंदर क्या देखना था, यह अगली पोस्ट के लिए छोड़ा गया है
1 टिप्पणियां
Hacker News की राय
Bryce Bostwick ऐप debugging और reverse engineering में सचमुच कमाल का और प्रेरक काम करते हैं
उनके बारे में YouTube से पता चला, और TikTok को सिर्फ बिल्ली के वीडियो दिखाने के लिए modify करने वाला वीडियो(https://youtu.be/YW3jL2gI9IE) देखकर मैंने Instagram को ऐसा modify करने की कोशिश की कि उसमें सिर्फ मेरे इस्तेमाल वाला messaging feature बचे और बाकी सब हट जाए
काफी पहले से Windhawk(https://windhawk.net/) स्टाइल में Windows को modify करने के तरीकों, खासकर modification और reverse engineering, में और गहराई से जाना चाहता था; Bryce iOS पर ऐसे काम को real-time step-by-step वीडियो में अच्छी तरह दिखाते हैं
देखा है कि Revanced से शानदार चीजें की जा सकती हैं, लेकिन ऐसे काम शुरू कैसे करें यह बताने वाली अच्छी guides ज्यादा नहीं दिखतीं
अगर आप प्रक्रिया को व्यवस्थित रूप से लिखकर रखें, तो मेरी दिलचस्पी होगी
फोटो डालने या दोस्तों से chat करने के लिए भी Reels के exposure में आना पड़े, यह मुझे पसंद नहीं
debugging में बाधा डालना और यहां तक कि debugging की बाधा को रोकने वाली चीज को फिर से रोकने की techniques DOS/Windows side पर बहुत पहले से आम रही हैं
पुराने cracking या unpacking materials देखें तो ये बातें अलग-अलग गहराई में मिलती हैं
यूज़र ऐप के behavior को कितनी आसानी से control कर सकता है, यह platform कितना user-hostile है इसके उलटे अनुपात में होता है
PT_DENY_ATTACH तो जैसे ठीक उसी user-hostility के लिए बनाया गया feature लगता है
मेरी जानकारी में Windows में ऐसा feature नहीं है; इसके बजाय ऐप को खुद से attach करवाने वाली technique इस्तेमाल होती है
https://www.x86matthew.com/view_post?id=selfdebug
https://anti-debug.checkpoint.com/techniques/interactive.htm...
यह थोड़ा हैरान करने वाला है कि Apple की App Store review direct system calls करने वाले apps को reject नहीं करती
Apple platforms पर system calls stable ABI नहीं हैं, इसलिए सभी system calls libSystem के जरिए होने चाहिए, और libSystem को bypass करके direct system call करने वाला app ऐसा काम कर रहा है जो उसे नहीं करना चाहिए
इसी तरह यहां लेखक ने code में
svc 0x80के बजायmov w16, #26क्यों खोजा, यह भी जानना चाहूंगाsvc 0x80कोई भी system call execute करने वाला instruction है, और ठीक कौन-सा call execute होगा यह x16 register पर निर्भर करता हैapp बहुत सारे unrelated system calls करेगा, इसलिए उस पर breakpoint लगाना उपयोगी नहीं होगा
कम से कम वीडियो में तो यही समझाया गया था
इसी वजह से SVC instruction खोजेंगे तो बहुत ज्यादा results आएंगे
X16 में move की जाने वाली exact system call ID ढूंढें तो सीधे मिल जाएगा
मैं ही post का लेखक हूं। कोई सवाल हो तो जवाब दूंगा। शेयर करने के लिए xmprt को धन्यवाद
अच्छा लगा कि आपने article version भी दिया
लेखक से कुछ बातें पूछना चाहूंगा: अगर सबसे मशहूर commercial tool Guardsquare ही है, तो क्या आपको लगता है कि वे इस तरह की आसान disassembly रोकने के लिए कुछ नया देते हैं?
यह भी जानना चाहूंगा कि TopWidgets इसी तरह की protection इस्तेमाल कर रहा था या यह उनके अपने बनाए स्तर की चीज थी
निजी तौर पर मैं Android इस्तेमाल करता हूं, इसलिए technically यह सीधे लागू नहीं होता, लेकिन iOS की low-level debugging कैसे काम करती है, यह सीखने में फिर भी बहुत value मिली
सबसे ऊपर वाला वीडियो अब तक देखे गए programming videos में सबसे अच्छे स्तर का है
pace तेज है, बिल्कुल सही background knowledge assume करता है, और ऐसे बेहतरीन demonstrations हैं जो वीडियो के flow को नहीं तोड़ते
शानदार article है
सच में जानना चाहूंगा कि यह कोई हद से ज्यादा paranoid normal app था, या शुरुआत से ही malware के शक में debug किया जा रहा app था
अगर ऐसा नहीं था, तो लगाया गया effort काफी ज्यादा लगता है
widgets के साथ यह काफी cool काम कर रहा था, इसलिए शायद वे उसे protect करना चाहते थे। हालांकि ऐसी strategies भी आखिरकार थोड़ी-थोड़ी leak होने लगी थीं
binary के अंदर कुछ दिलचस्प चीजें भी थीं
एक समय मैं यह समझने की कोशिश कर रहा था कि Windows
.isodownload करता हुआ दिखने वाला code मैं क्यों देख रहा हूं; असल में वही था और यह network speed test widget में इस्तेमाल हो रहा था“PT_DENY_ATTACH bypass करना (hard mode)” से भी कठिन mode है
पहले macOS पर मैंने kernel patch करके PT_DENY_ATTACH को कुछ भी न करने वाला बना दिया था
Mac पर patched kernel चलाना वास्तव में काफी आसान है, लेकिन iOS पर KTRR जैसी चीजों की वजह से यह शायद कहीं ज्यादा झंझट वाला होगा
XNU technically open source है, लेकिन फिर से compile करने के बजाय hex editor से patch लगाना आसान था
unsigned code pages और RWX allow करके JIT भी संभव बनाया जा सकता है
अगर “jailbreak on करके चलाने पर पूरा phone crash हो जाता है”, तो क्या इसे store में malware के रूप में report नहीं करना चाहिए?
phone crash करना साफ तौर पर malware जैसा behavior है, और यह भी शक करना चाहिए कि छिपाने के लिए और कौन-से malicious actions हो सकते हैं
ऐसे कचरे को रोकना ही तो Apple के closed ecosystem का justification नहीं था?
Apple को jailbroken phone पर app crash होने की ज्यादा परवाह नहीं होगी
com.apple.tw.twrr notification सच में curious बनाती है
यह
com.appleसे क्यों शुरू होती है?यहां जिस app की बात है वह Apple app नहीं, Top Widgets नाम का app लगता है
collisions से बचने के लिए इस तरह का “fully qualified name” इस्तेमाल करना convention है
इस case में लगता है developer ने संयोग से वही prefix चुन लिया
tools ही अलग हैं, यह बिल्कुल वैसा ही लगता है जैसे 1980s में boot tracing से Apple II copy protection तोड़ी जाती थी
कुछ चीजें नहीं बदलतीं