
In disputes on the Internet and in real life, arguments that are supported by evidence β screenshots, photos, recording messages / calls, video recordings, etc. β have the greatest weight.
β . . ?
, , - - , , , .
β screenlife, . : , .
(, ). : / , . , , . : , / .
: screenlife, , , .
, , β Frida, JavaScript . , , DeepFace.
, Frida
, Frida 18 .
Frida β (Dynamic Binary Instrumentation, DBI), runtime JavaScript blackbox / β hooking tracing , , . Frida . Frida , iOS.
/proof
: iPhone 6s iOS 13.2.3
: Instagram (v126.0.0.13.120)
: , .
, . β .
TL;DR
- Frida
β iOS- Jailbreakβ.
:
, , . .
jailbreak, .
, , . UI , ? UI Instagram:
Madonna ( ):

, ( ):

( ):

, ( origUser β original User), ( replUser β replicated User), UI , origUser ( , ). replUser, , , . , , . , ID origUser replUser, , .
IPA
, Frida-, ( IPA Instagram). :
- Mac: Apple configurator 2AppStore, . .
- iPhone jailbreak iOS, frida-ios-dump . , Frida. , IPA Instagram. Frida .
, . iOS bundle . Mach-O 64-bit arm64 :
- Instagram.App/Instagramβ
- Instagram.app/Frameworks/InstagramAppCoreFramework.framework/InstagramAppCoreFrameworkβ Instagram
- Instagram.app/Frameworks/FBSharedFramework.framework/FBSharedFrameworkβ shared Facebook, InstagramAppCoreFramework Instagram.
(Instagram)
β Insagram.App/Instagram. , IDA Pro.
Instagram, , ( 364), Instagram β :

β . , .
(InstagramAppCoreFramework FBSharedFramework)
InstagramAppCoreFramework, Instagram.
, FBSharedFramework Instagram InstagramAppCoreFramework, (User, Direct Messages, Message ), controller view InstagramAppCoreFramework.
, direct . , βMessageβ origUser, direct replUser.
Doxygen
InstagramAppCoreFramework IDA Pro, , 250000 , , . -, doxygen- header- Objective-C . header- classdumpios, ARM64. iPhone jailbreak, SSH USB IPA Instagram :
iPhone:~/insta $ mkdir headers
iPhone:~/insta $ cp Payload/Instagram.app/Frameworks/InstagramAppCoreFramework.framework/InstagramAppCoreFramework ./headers
iPhone:~/insta $ cp Payload/Instagram.app/Frameworks/FBSharedFramework.framework/FBSharedFramework ./headers
iPhone:~/insta $ cd headers
iPhone:~/insta/headers $ classdumpios -H InstagramAppCoreFramework -o IG_headers
iPhone:~/insta/headers $ classdumpios -H FBSharedFramework -o FB_headers
iPhone:~/insta/headers $ tar -czvf IG_headers.tar.gz IG_headers
iPhone:~/insta/headers $ tar -czvf FB_headers.tar.gz FB_headers
header- iPhone , , doxygen :
Host@Host:~/insta$ mkdir docs && cd docs
Host@Host:~/insta/docs $ scp -P <PORT> root@<IP>:</path/to/instagram>/insta/headers/IG_headers.tar.gz .
Host@Host:~/insta/docs $ scp -P <PORT> root@<IP>:</path/to/instagram>/insta/headers/FB_headers.tar.gz .
Host@Host:~/insta/docs $ tar xf IG_headers.tar.gz
Host@Host:~/insta/docs $ tar xf FB_headers.tar.gz
Host@Host:~/insta/docs $ cp </path/to/dox.template> .
Host@Host:~/insta/docs $ doxygen dox.template
doxygen- , . .
, InstagramAppCoreFramework FBSharedFramework:

, IGAuthUserParser:

, .
Frida-
, . , , Frida- , , , , backtrace, . . . trace-, .
Python- Frida, :
~ $ pip install --upgrade frida frida-tools
, frida-server. , , ( JB) ( JB).
- inputView:didTapStickerButton: IGDirectThreadViewController. ? , , . , direct ( , , ). , , , , Frida. NativeFunction :
var func = ObjC.classes.IGDirectThreadViewController["inputView:didTapStickerButton:"].implementation;
hook, :
Interceptor.attach(func, {
    onEnter: function(args) {
        console.log("-[IGDirectThreadViewController inputView:didTapStickerButton:] => onEnter");
   },
    onLeave: function(retval) {
        console.log("-[IGDirectThreadViewController inputView:didTapStickerButton:] <= onLeave");
    }
}
, .
, , . , , , .
hook, , , . hook β . . :
function addTracer(className, methodName) {
    
    var impl = ObjC.classes[className][methodName].implementation;
    Interceptor.attach(impl, {
        onEnter: function(a) {
            this.log = []; 
            this.log.push('(' + a[0] + ',' + Memory.readUtf8String(a[1]) + ') ' + className + ' ' + methodName); 
            if (methodName.indexOf(':') !== -1) { 
                var params = methodName.split(':');
                params[0] = params[0].split(' ')[1];
                
                for (var i = 0; i < params.length - 1; i++) {
                    try {
                        this.log.push(params[i] + ': ' + new ObjC.Object(a[2 + i]).toString());
                    } catch (e) {
                        this.log.push(params[i] + ': ' + a[2 + i].toString());
                    }
                }
            }
            
            this.log.push(
                Thread.backtrace(this.context, Backtracer.ACCURATE)
                    .map(DebugSymbol.fromAddress)
                    .join('\n')
            );
        },
        onLeave: function(r) {
            
            try {
                this.log.push('RET: ' + new ObjC.Object(r).toString());
            } catch (e) {
                this.log.push('RET: ' + r.toString());
            }
            console.log(this.log.join('\n') + '\n');
        }
    });
}
:
addTracer("IGDirectThreadViewController", "- inputView:didTapStickerButton:");
, ( Frida- , USB):
$ frida -U -n Instagram -l </path/to/script> --no-pause
direct ( ). :
(0x1269aea00,inputView:didTapStickerButton:) IGDirectThreadViewController - inputView:didTapStickerButton:
inputView: <IGDirectComposer: 0x125d241b0; frame = (0 607; 375 60); text = ''; autoresize = H; layer = <CALayer: 0x281ef5fc0>>
didTapStickerButton: <IGDirectComposerButton: 0x127a5e210; baseClass = UIButton; frame = (319 10; 24 24); opaque = NO; tintColor = <UIDynamicProviderColor: 0x281e29dc0; provider = <__NSMallocBlock__: 0x2810cfdb0>>; layer = <CALayer: 0x281e37900>>
0x1072df1dc InstagramAppCoreFramework!IGHandleURLForIGInstagramToast
0x18743bab0 UIKitCore!-[UIApplication sendAction:to:from:forEvent:]
0x186e738ac UIKitCore!-[UIControl sendAction:to:forEvent:]
0x186e73c10 UIKitCore!-[UIControl _sendActionsForEvents:withEvent:]
0x186e72c2c UIKitCore!-[UIControl touchesEnded:withEvent:]
0x1019378ac FBSharedFramework!IGCrashReportProcessorLatestUploadError
0x187475288 UIKitCore!-[UIWindow _sendTouchesForEvent:]
0x1874765c8 UIKitCore!-[UIWindow sendEvent:]
0x187452b78 UIKitCore!-[UIApplication sendEvent:]
0x1012e0784 FBSharedFramework!IGALLoggerSetTrackingNodeForView
0x1874caef8 UIKitCore!__dispatchPreprocessedEventFromEventQueue
0x1874cd454 UIKitCore!__handleEventQueueInternal
0x1874c62c8 UIKitCore!__handleHIDEventFetcherDrain
0x18334f7c4 CoreFoundation!__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
0x18334f71c CoreFoundation!__CFRunLoopDoSource0
0x18334eeb4 CoreFoundation!__CFRunLoopDoSources0
RET: nil
direct
, Instagram. .
Instagram direct ( , ) IGDirectThread ( "direct ", "direct thread", "" ).

, , direct thread β _threadId. ID. . , , direct , .
_metadata. ( _users), direct thread.
IGUser. , . _pk, . _pk , , 
, UI IGDirectThread, β IGDirectThreadViewController , , . β , .
, direct IGDirectThreadViewController. , . -[IGDirectThreadViewController initWithUserSession:thread:entryPoint:perfComponents:]. Frida-hook , , . , IGDirectThreadViewController:

IGDirectThread. , IGDirectThread , , direct , .
direct
, , : origUser, IGDirectThread , replUser. Instagram , origUser replUser . . β _pk , IGDirectThread, _users ( _metadata) _pk. β hook _threadId (, ), direct thread ID.
, direct thread β IGDirectThread , direct , ( _users):
var IGDirectThreadViewControllerInitWithUserSession = ObjC.classes.IGDirectThreadViewController["- initWithUserSession:thread:entryPoint:perfComponents:"].implementation;
Interceptor.attach(IGDirectThreadViewControllerInitWithUserSession, {
    onEnter: function(args) {
        this.thread = new ObjC.Object(args[3]);
        
        [origUser, replUser].forEach(function (user) {
            var users = this.thread.$ivars["_metadata"].$ivars["_users"];
            if (users.count() == 1 && users.objectAtIndex_(0).$ivars["_pk"] == user.pk && user.thread == undefined) {
                user.thread = this.thread.retain();
            }
        }, this);
        
        if (origUser.threadId == undefined || replUser.threadId == undefined) {
            return;
        }
        
        if (this.thread.$ivars["_threadId"].equals(origUser.threadId)) {
            
            args[3] = replUser.thread.retain();
            
            replaceState = true;
            console.log(
                FgGreen + "[+]" + Reset +
                " Thread " +
                origUser.threadId +
                " spoofed with " +
                replUser.threadId +
                "!"
            );
        }
    }
});
Frida- ( , ) direct origUser, replUser! , . .
IGDirectThreadViewController runtime, β _viewModel. ? IGDirectThreadViewControllerViewModel, _leftAlignedTitleViewModel , _leftAlignedTitleViewModel->_titleButton->_titleView->text, , (.. , direct ). , _viewModel, origUser ( ), direct origUser (, )?
, . origUser β , . replUser replUser. , β -[IGDirectViewController _updateThreadNavigationBar]. . direct origUser replUser, origUser, .
var IGDirectThreadViewControllerUpdateNavigationBar = ObjC.classes.IGDirectThreadViewController["- _updateThreadNavigationBar"].implementation;
Interceptor.attach(IGDirectThreadViewControllerUpdateNavigationBar, {
    onLeave: function(retval) {
        
        if (replaceState && this.controller.$ivars["_threadId"].equals(replUser.threadId)) {
            this.controller.$ivars["_viewModel"] = origUser.viewModel.retain();
        }
        if (DEBUG) console.log("IGDirectThreadViewController[onLeave]: -_updateNavigationBar");
    }
});
.
β IGUser _profilePicURL. direct origUser replUser origUser, . , .
.
, . production-ready , , , .
350 JavaScript . , , β ;)
, , (AR), .
- β ;)
@d1g1 ! :)
P.S.