1 पॉइंट द्वारा GN⁺ 2025-02-19 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • iOS ऐप reverse engineering के लिए आम तौर पर चल रहे ऐप को observe और manipulate कर पाना ज़रूरी होता है, लेकिन इस widget ऐप में debugger block, code injection block, और jailbreak detection तीनों साथ इस्तेमाल किए गए थे
  • मुख्य block ptrace के PT_DENY_ATTACH या उसी प्रभाव वाले direct system call (svc #0x80) से लागू किया जा सकता है, इसलिए केवल ptrace breakpoint से इसे पकड़ा नहीं जा सकता
  • direct system call को bypass करने के लिए binary में mov w16, #26 pattern ढूँढकर 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 किया जा सकता है
  • इसी तरीके से इस ऐप पर debugserver attach करने की कोशिश करने पर Segmentation fault हुआ और attach विफल हो गया
  • इसकी वजह ptrace के PT_DENY_ATTACH request से जुड़ी थी
    • ptrace iOS में private API है और macOS में public API
    • PT_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 का ptrace symbol ढूँढना पड़ता है
    • इस तरीके को ptrace पर breakpoint लगाकर और thread return से कॉल skip करके काफ़ी आसानी से bypass किया जा सकता है

आसान bypass काम क्यों नहीं आया

  • PT_DENY_ATTACH केवल कॉल होने के बाद debugger को रोकता है, इसलिए ऐप कोड चलने से पहले attach कर लिया जाए तो bypass point बनाया जा सकता है
  • debugserver को process पर सीधे attach करने के बजाय पहले चलाकर, lldb में process attach --name TopWidget --waitfor से ऐप launch का इंतज़ार करने पर ऐप कोड चलने से पहले attach किया जा सकता है
  • लेकिन इस ऐप में b ptrace breakpoint शुरू में resolve ही नहीं हुआ, और बाद में resolve होने पर भी hit हुए बिना ऐप बंद हो गया
  • वजह यह थी कि ऐप ptrace function call के बजाय उसी असर वाले direct system call का इस्तेमाल कर रहा था

direct system call की जगह ढूँढना

  • ptrace function की disassembly में मुख्य system call svc #0x80 शामिल होता है
    • x0 में PT_DENY_ATTACH का मान 31 होता है
    • x1, x2, x3 में इस्तेमाल न होने वाले argument 0 होते हैं
    • x16 में ptrace system call number 26 होता है
  • ऐप ptrace function को कॉल किए बिना inline assembly से वही register values सेट करके सीधे svc #0x80 चला सकता है
    • यह तरीका dlopen, dlsym जैसी संदिग्ध private API lookup से बचाता है
    • और ptrace जैसे common function पर breakpoint लगाकर पकड़ना मुश्किल बना देता है
  • bypass करने के लिए decrypted app binary को disassembler में खोलकर ptrace system call की location खोजनी पड़ी
  • खोज का target mov x16, #26 या उसी register के 32-bit view mov w16, #26 था
    • armconverter.com से mov x16, #26 के bytes 50 03 80 D2 लेकर binary search में इस्तेमाल किया जा सकता है
    • mov x16, #26 पर कोई result नहीं मिला, जबकि mov w16, #26 search में 4 result मिले
  • उनमें से दो result के आस-पास की instructions अपेक्षित pattern से मेल नहीं खाती थीं, और तीसरे result में नीचे जैसा code मिला
    • MOV X0, #0x1F
    • MOV X1, #0
    • MOV X2, #0
    • MOV X3, #0
    • MOV W16, #0x1A
    • SVC 0x80
  • चौथा result उसी function की दूसरी branch था, और इसी function को debugger attach block की जगह के रूप में पहचाना गया

svc instruction skip करना

  • disassembler में मिले svc addresses 0x102A2BB14 और 0x102A2BB68 थे
  • lldb में binary-relative address को actual load address में बदलने के लिए -s TopWidget के साथ breakpoint सेट किया गया
    • br s -a 0x102A2BB14 -s TopWidget
    • br s -a 0x102A2BB68 -s TopWidget
  • execution जारी रखने पर svc #0x80 की जगह breakpoint hit हुआ
  • सबसे आसान bypass यह था कि अगले instruction address पर jump करके system call को execute ही न होने दिया जाए
    • उदाहरण में current instruction के अगले address 0x10327bb18 पर jump *0x10327bb18 चलाया गया
  • इस प्रक्रिया के बाद debugger attached स्थिति में ऐप के अंदर प्रवेश किया जा सका

फ़ोन को soft-reboot कराने वाला behavior

  • debugger attach bypass करने के बाद भी ऐप ने फ़ोन को soft-reboot/respring कराने वाला सुरक्षा behavior चलाया
  • इस बार lldb अभी भी attach था, इसलिए process को SIGKILL मिलने की स्थिति और stacktrace देखा जा सका
  • stacktrace में screen content capture का flow दिखाई दिया
    • QuartzCore का CARenderServerSnapshot
    • UIKitCore का _UISnapshotScreenWindowsRectAfterCommit
    • ऐप के अंदर TopWidget का unnamed symbol
  • lldb image lookup से runtime address को binary-relative address 0x100041898 में बदलकर 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.twrr notification से जुड़ी है, और फ़ोन 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 में देखने पर BRK instruction मिला, जो 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 करना पड़ता है, लेकिन उसके बाद Flex injected स्थिति में ऐप के अंदर जाया जा सकता है

अंतिम स्थिति

  • आख़िर में ऐप ऐसी स्थिति में पहुँचा जहाँ debugger attach, jailbreak detection bypass, और code injection तीनों संभव हो गए
  • वास्तव में ऐप के अंदर क्या देखना था, यह अगली पोस्ट के लिए छोड़ा गया है

1 टिप्पणियां

 
GN⁺ 2025-02-19
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 वीडियो में अच्छी तरह दिखाते हैं

    • अगर Android side पर भी कोई ऐसा व्यक्ति हो, तो मैं और सीखना चाहूंगा
      देखा है कि 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...

    • सही है। PT_DENY_ATTACH असल में Apple ने पहले iTunes के DRM solution के हिस्से के रूप में सीधे बनाया था
  • यह थोड़ा हैरान करने वाला है कि 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 लगाना उपयोगी नहीं होगा
      कम से कम वीडियो में तो यही समझाया गया था
    • compiler कभी-कभी system call wrapper को inline कर सकता है, इसलिए static तौर पर verify करना इतना आसान नहीं है
      इसी वजह से SVC instruction खोजेंगे तो बहुत ज्यादा results आएंगे
      X16 में move की जाने वाली exact system call ID ढूंढें तो सीधे मिल जाएगा
  • मैं ही post का लेखक हूं। कोई सवाल हो तो जवाब दूंगा। शेयर करने के लिए xmprt को धन्यवाद

    • YouTube पर वीडियो देखा था, दिलचस्प था
      अच्छा लगा कि आपने article version भी दिया
    • बहुत दिलचस्प article था, और ऐसे low-level phone reverse engineering articles मैं हमेशा देखना चाहता था
      लेखक से कुछ बातें पूछना चाहूंगा: अगर सबसे मशहूर commercial tool Guardsquare ही है, तो क्या आपको लगता है कि वे इस तरह की आसान disassembly रोकने के लिए कुछ नया देते हैं?
      यह भी जानना चाहूंगा कि TopWidgets इसी तरह की protection इस्तेमाल कर रहा था या यह उनके अपने बनाए स्तर की चीज थी
    • वीडियो बहुत दिलचस्प हैं, और हैरानी है कि ज्यादा लोगों ने उन्हें देखा या article नहीं पढ़ा
      निजी तौर पर मैं Android इस्तेमाल करता हूं, इसलिए technically यह सीधे लागू नहीं होता, लेकिन iOS की low-level debugging कैसे काम करती है, यह सीखने में फिर भी बहुत value मिली
    • जानना चाहूंगा कि iOS में PTRACE_SYSCALL जैसा कुछ है क्या, जिससे system call entry point पर hook करके return value बदली जा सके, या यह detect किया जा सके कि SVC कहां से हो रहा है
  • सबसे ऊपर वाला वीडियो अब तक देखे गए programming videos में सबसे अच्छे स्तर का है
    pace तेज है, बिल्कुल सही background knowledge assume करता है, और ऐसे बेहतरीन demonstrations हैं जो वीडियो के flow को नहीं तोड़ते

  • शानदार article है
    सच में जानना चाहूंगा कि यह कोई हद से ज्यादा paranoid normal app था, या शुरुआत से ही malware के शक में debug किया जा रहा app था
    अगर ऐसा नहीं था, तो लगाया गया effort काफी ज्यादा लगता है

    • मेरे आकलन में यह बस हद से ज्यादा paranoid app के करीब है
      widgets के साथ यह काफी cool काम कर रहा था, इसलिए शायद वे उसे protect करना चाहते थे। हालांकि ऐसी strategies भी आखिरकार थोड़ी-थोड़ी leak होने लगी थीं
      binary के अंदर कुछ दिलचस्प चीजें भी थीं
      एक समय मैं यह समझने की कोशिश कर रहा था कि Windows .iso download करता हुआ दिखने वाला code मैं क्यों देख रहा हूं; असल में वही था और यह network speed test widget में इस्तेमाल हो रहा था
    • या यह भी हो सकता है कि अगर app को किसी दूसरे logo आदि के साथ recompile किया गया हो, तो copyright infringement साबित करने की कोशिश हो
  • “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 लगाना आसान था

    • kernel task port का इस्तेमाल करके proc structure में bit flip भी किया जा सकता है
      unsigned code pages और RWX allow करके JIT भी संभव बनाया जा सकता है
  • अगर “jailbreak on करके चलाने पर पूरा phone crash हो जाता है”, तो क्या इसे store में malware के रूप में report नहीं करना चाहिए?
    phone crash करना साफ तौर पर malware जैसा behavior है, और यह भी शक करना चाहिए कि छिपाने के लिए और कौन-से malicious actions हो सकते हैं
    ऐसे कचरे को रोकना ही तो Apple के closed ecosystem का justification नहीं था?

    • “jailbreak on करके” का मतलब है कि आप closed ecosystem के बाहर हैं
      Apple को jailbroken phone पर app crash होने की ज्यादा परवाह नहीं होगी
  • com.apple.tw.twrr notification सच में curious बनाती है
    यह com.apple से क्यों शुरू होती है?
    यहां जिस app की बात है वह Apple app नहीं, Top Widgets नाम का app लगता है

    • notification name arbitrary string होता है
      collisions से बचने के लिए इस तरह का “fully qualified name” इस्तेमाल करना convention है
      इस case में लगता है developer ने संयोग से वही prefix चुन लिया
  • tools ही अलग हैं, यह बिल्कुल वैसा ही लगता है जैसे 1980s में boot tracing से Apple II copy protection तोड़ी जाती थी
    कुछ चीजें नहीं बदलतीं