0

I am trying to listen for a javascript callback from a 3rd party app on my site. The app is minified so it is quite hard to reverse engineer. However, having used the Chrome debugger, the callback I want to capture is below, is there any way, I can trigger a function when that 'CollectEvent' callback is fired, with access to the 'email' variable? You can see in the console, that the callbacks are being created on the window, although of course they are named differently each time the code runs.

Recognising that I cannot edit that code directly as it is part of a 3rd party library.

!function() {
    var _0x14bdc8 = {
        'CollectEvent': function(_0x4a9e64, _0x3ac5b7) {
            if (_0x4a9e64) {
                _0x14bdc8[_0x304d('0xa7')] && (_0x30053a('COUPON_CODE_COOKIE_NAME', _0x4a9e64[_0x304d('0xd7')], 0x1),
                _0x14bdc8[_0x304d('0x6a')]());
                var _0x562cf7 = {
                    'shopId': _0x14bdc8[_0x304d('0xc2')],
                    'campaignId': _0x14bdc8[_0x304d('0x79')],
                    'email': encodeURIComponent(_0x4a9e64[_0x304d('0x23')]),
                    'code': _0x4a9e64['code'],
                    'customFields': encodeURIComponent(JSON[_0x304d('0x3')](_0x3ac5b7)),
                    'domain': window[_0x304d('0x73')][_0x304d('0x4a')],
                    'currentUrl': window[_0x304d('0x73')][_0x304d('0x6b')]
                };
                _0x14bdc8[_0x304d('0xa0')](_0x986b46 + '/api/wheelioapp/collectemail', _0x562cf7, function(_0xea4ea9) {
                    _0xea4ea9[_0x304d('0x89')] && _0x14bdc8[_0x304d('0x8f')](!0x1, !0x1, !0x0, !0x1);
                });
            } else
                alert(_0x304d('0x80'));
        },
    ...
    }
}

You can see here the Wheelio app object in the console and the callbacks which have been created (although they have different names each session).

enter image description here

6
  • What "3rd party app?" Is that a plugin, like a jQuery plugin or something? What are you trying to do in the first place? Commented Sep 23, 2020 at 9:38
  • @JeremyThille It's a pop up on my Shopify site that collects people's email addresses as they subscribe to our newsletter. We want to link our session monitoring and email capture, so from our analytics tools, we can say that email [email protected] matches browse session abc. The "3rd party app" doesn't use JQuery. Commented Sep 23, 2020 at 9:41
  • Oh, I see :/ Unfortunately I know absolutely 0 about Shopify! However, if you can edit this code above, you could hack this thing by making the _0x562cf7 object global : window["dataYouNeed"] = _0x562cf7, then you can access it from anywhere : window.dataYouNeed.email. EDIT : Forget that, you said you could not edit this code. Then I see no solution :( Commented Sep 23, 2020 at 9:52
  • @JeremyThille OK, thanks for looking though. I suppose I wonder whether there is an async pattern to identify how the callback will be generated and then chain a promise type chain off the back of that. Commented Sep 23, 2020 at 11:11
  • What do you want: to read the email (log it somewhere) or to change it inside this callback? Commented Sep 28, 2020 at 10:52

1 Answer 1

2
+200

I just need to log it

Well, ok. We can't change functions created on-the-fly, but we can change other window functions.

For example we can use encodeURIComponent. See this line:

'email': encodeURIComponent(_0x4a9e64[_0x304d('0x23')]),

It means that somehow the email will go into the encodeURIComponent. Good, because we can read it there:

/* At the beginning */
// This is helper function, detects correct email:
function validateEmail(email) {
    const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(String(email).toLowerCase());
}
// Keep old function
let oldEncodeURIComponent = window.encodeURIComponent;
// Crete new one
window.encodeURIComponent = (data) => {
  if (validateEmail(data)) {
    // Gotcha!
    console.log('[encodeURIComponent]', data);
  }
  return oldEncodeURIComponent(data);
}

/* Here program works as normal, but creates lots of logs... */

/* In the end */
// If we can understand when we need to stop looking for email,
//   we will disconnect our function:
window.encodeURIComponent = oldEncodeURIComponent;

So the idea is to read all data passing thru encodeURIComponent.

P.S. Email validator is here

Sign up to request clarification or add additional context in comments.

2 Comments

Really neat - thanks. I'll see if I can get this to work :)
This is a neat solution! Another possible solution in similar fashion is to override XMLHttpRequest API or install a service worker on your own site that censors outbound traffic. Still a kind of interceptor, just that it's more general, works when encodeURIComponent is not used.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.